3.5. Facade
The Facade pattern is a structural design pattern that provides a simplified, unified interface to a complex subsystem or a group of related interfaces. It helps reduce coupling between the client code and the subsystem, making it easier to use and understand the functionality provided by the subsystem.
The Facade pattern is typically used when:
- You want to provide a simple interface to a complex subsystem.
- You want to reduce coupling between the client code and the subsystem.
- You want to better organize the subsystem by dividing it into layers or components.
To implement the Facade pattern, follow these steps:
- Identify the subsystem or group of related interfaces that need to be simplified.
- Create a facade class that implements a simplified, unified interface for the subsystem.
- Implement the methods of the facade class by delegating calls to the appropriate subsystem components.
- Use the facade class in the client code instead of directly accessing the subsystem components.
Here’s a simple example of the Facade pattern in Java:
// Complex subsystem components
public class SubsystemA {
public void operationA() {
System.out.println("SubsystemA operationA");
}
}
public class SubsystemB {
public void operationB() {
System.out.println("SubsystemB operationB");
}
}
public class SubsystemC {
public void operationC() {
System.out.println("SubsystemC operationC");
}
}
// Facade class
public class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
private SubsystemC subsystemC;
public Facade() {
subsystemA = new SubsystemA();
subsystemB = new SubsystemB();
subsystemC = new SubsystemC();
}
public void simplifiedOperation() {
subsystemA.operationA();
subsystemB.operationB();
subsystemC.operationC();
}
}
// Client code
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.simplifiedOperation(); // Outputs: "SubsystemA operationA", "SubsystemB operationB", "SubsystemC operationC"
}
}
In this example, the SubsystemA
, SubsystemB
, and SubsystemC
classes represent the complex subsystem components. The Facade
class provides a simplified interface, implementing the simplifiedOperation
method that delegates calls to the appropriate subsystem components.
Advantages of the Facade pattern:
- Simplified interface: The Facade pattern provides a simplified interface to a complex subsystem, making it easier for clients to use and understand the functionality.
- Reduced coupling: The pattern reduces coupling between the client code and the subsystem, promoting a cleaner and more modular codebase.
Disadvantages of the Facade pattern:
- Limited functionality: The simplified interface provided by the facade may not expose all the functionality of the subsystem. However, this can be considered a trade-off for the simplicity it offers.
When using the Facade pattern, consider its benefits and trade-offs carefully. Use the pattern when you want to provide a simpler interface to a complex subsystem or when you want to reduce coupling between the client code and the subsystem. Keep in mind that the simplified interface may not expose all the functionality of the subsystem, so ensure it meets the needs of the client code.
Use case: Facade Pattern for Bank Account Operations
We have a simple banking system that consists of multiple classes like Account, Customer, Transaction, and Report. To simplify the interaction with these classes and hide their complexity, we will create a Facade class called BankFacade. The BankFacade class will provide a unified and simpler interface for users of the banking system.
Here’s a basic implementation of the Facade pattern in Java:
- Account.java
public class Account {
private int accountId;
private double balance;
public Account(int accountId, double balance) {
this.accountId = accountId;
this.balance = balance;
}
public int getAccountId() {
return accountId;
}
public double getBalance() {
return balance;
}
public void deposit(double amount) {
balance += amount;
}
public void withdraw(double amount) {
balance -= amount;
}
}
2. Customer.java
public class Customer {
private int customerId;
private String name;
public Customer(int customerId, String name) {
this.customerId = customerId;
this.name = name;
}
public int getCustomerId() {
return customerId;
}
public String getName() {
return name;
}
}
3. Transaction.java
public class Transaction {
public void transfer(Account fromAccount, Account toAccount, double amount) {
fromAccount.withdraw(amount);
toAccount.deposit(amount);
}
}
4. Report.java
public class Report {
public void displayBalance(Account account) {
System.out.println("Account ID: " + account.getAccountId() + ", Balance: " + account.getBalance());
}
}
5. BankFacade.java (Facade class)
public class BankFacade {
private Account account;
private Customer customer;
private Transaction transaction;
private Report report;
public BankFacade(int accountId, double initialBalance, int customerId, String name) {
this.account = new Account(accountId, initialBalance);
this.customer = new Customer(customerId, name);
this.transaction = new Transaction();
this.report = new Report();
}
public void deposit(double amount) {
account.deposit(amount);
}
public void withdraw(double amount) {
account.withdraw(amount);
}
public void transfer(BankFacade toBankFacade, double amount) {
transaction.transfer(this.account, toBankFacade.account, amount);
}
public void displayBalance() {
report.displayBalance(account);
}
}
6. Main.java (Example usage)
public class Main {
public static void main(String[] args) {
BankFacade customer1 = new BankFacade(1, 1000, 101, "John Doe");
BankFacade customer2 = new BankFacade(2, 500, 102, "Jane Smith");
customer1.deposit(500);
customer1.displayBalance();
customer1.withdraw(300);
customer1.displayBalance();
customer1.transfer(customer2, 200);
customer1.displayBalance();
customer2.displayBalance();
}
}
In this example, we have implemented a simple banking system using the Facade pattern. The BankFacade class hides the complexity of the underlying classes (Account, Customer, Transaction, and Report) and provides a simple interface for users to interact with the banking system.
Now, let’s continue by adding more functionality to our banking system.
7. Add a method to display customer information in the Report.java class:
public void displayCustomerInfo(Customer customer) {
System.out.println("Customer ID: " + customer.getCustomerId() + ", Name: " + customer.getName());
}
8. Add a method to display customer information in the BankFacade.java class:
public void displayCustomerInfo() {
report.displayCustomerInfo(customer);
}
9. Update the Main.java class to demonstrate the new functionality:
public class Main {
public static void main(String[] args) {
BankFacade customer1 = new BankFacade(1, 1000, 101, "John Doe");
BankFacade customer2 = new BankFacade(2, 500, 102, "Jane Smith");
customer1.deposit(500);
customer1.displayBalance();
customer1.withdraw(300);
customer1.displayBalance();
customer1.transfer(customer2, 200);
customer1.displayBalance();
customer2.displayBalance();
customer1.displayCustomerInfo();
customer2.displayCustomerInfo();
}
}
By running the updated Main.java, you will see the output:
Account ID: 1, Balance: 1500.0
Account ID: 1, Balance: 1200.0
Account ID: 1, Balance: 1000.0
Account ID: 2, Balance: 700.0
Customer ID: 101, Name: John Doe
Customer ID: 102, Name: Jane Smith
In summary, we have expanded our banking system by adding the functionality to display customer information. The BankFacade class continues to provide a simplified interface, making it easy for users to interact with the banking system.
Note: For complete list of design patterns click here