Facade Design Pattern

The Facade Design Pattern provides a simple unified interface of a complex system to a client to abstract the complexity and make it easier for client to use. Facade defines a single high level interface that makes the subsystem easier to use. Facade pattern comes under structural pattern as it provides one of the best ways to hide internal complexities from client.

A facade is a composition of subsystems and uses delegates the tasks to subsystems. It may also add some logic of it's own before delegating work to subsystem. However, it doesn't hide the subsystem interfaces form the client. A client is free to directly interact with subsystem, it is on client whether to use facade or not.
In this tutorial, we'll explore the Facade Design Pattern in Java, covering its structure, implementation, best practices, and advantages.


Structure of the Facade Design Pattern

The Facade Design Pattern involves the following key components:
  • Facade : This is the central class that provides a simplified and unified interface to the client. The facade delegates client requests to the appropriate subsystem components.

  • Subsystem Classes : These are the individual classes or components that make up the subsystem. The facade doesn't encapsulate these classes but rather provides a higher-level interface to them.

  • Client : This is the class or module that interacts with the facade to access the subsystem's functionality. The client is shielded from the complexities of the subsystem's internal structure.

Advantages of Facade Design Pattern

  • Encapsulation of Subsystem Complexity : By offering a layer of abstraction, the pattern encapsulates the subsystem's complexity. Clients don't have to comprehend the inner workings of the subsystem in order to use the facade's simplified interface.

  • Simplified Client Interface : The main benefit of the Facade pattern is the client interface's simplification. The single front that interacts with clients protects them from the intricacies and specifics of the subsystem.

  • Enhanced Code Readability : By giving clients a simple and straightforward access point, the usage of a façade improves code readability. Because the façade methods are named after high-level functions, developers will find it easy to comprehend and utilize the subsystem

  • Promotion of Decoupling : The client and the subsystem are encouraged to decouple by the facade pattern. As long as the interface of the facade stays consistent, changes made to the subsystem, such as adjustments to individual parts or their internal organization, have no effect on the client.

  • Single Point of Contact for Clients : The façade serves as the client's single point of contact while interacting with the subsystem. This one point of contact helps create a system that is easier to administer and better structured.

  • Subsystem Evolution without Client Impact : Subsystem elements are capable of developing separately from client code. Clients do not need to make any changes in order to adopt new versions of the subsystem as long as the interface of the façade is consistent.

  • Reduced Dependency on Subsystem Details : Clients are less dependent on the details of the subsystem. The facade shields clients from the specifics of individual components, promoting a separation of concerns.

When we should use Facade Pattern

  • When we want to provide single unified interface to client to interact with a complex subsystem.
  • When we want to hide the internal complexities of system.
  • When we want to decouple the client's implementation form subsystems.

Implementation of Facade Design Pattern

Facade Design Pattern UML Diagram

First of all we will define the subsystems of a order fulfillment systems.

ReserveInventory.java

This class reserves the item for this order.

public class ReserveInventory {
    public void reserveInventory(){
        System.out.println("Blocking Item for Customer.");
    }
}

ReservePayment.java

This class deducts the order amount form customers credit card.

public class ReservePayment {
   public void receivePayment(){
      System.out.println("Deducting amount from customer's credit card.");
   }
}

DeliverySystem.java

This class manages the delivery of an item to customers address.

public class DeliverySystem {
   public void deliverOrder(){
      System.out.println("Deliverying Item to customer's address.");
   }
}

CancelOrder.java

This class cancels customers order.

public class CancelOrder {
    public void cancelOrder(){
        System.out.println("Cancelling order.");
    }
}

RefundPayment.java

This class refunds the order amount to customer on order cancellation.

public class RefundPayment {
   public void refundOrderAmount(){
      System.out.println("Refunding Order Amount to Customer.");
   }
}

Now, to place an order we have to first reserve inventory and the reserve payment(deduct customers credit's card) and finally deliver the item to customer. To hide the complexity of placing order from a third party client we will provide a simple method "placeOrder" in OrderManagementFacade which will handle every thing required for placing an order. Similarly, we will provide "cancelOrder" method in facade for cancelling an order. Order Management Facade hides the complexities of fulfillment subsystems form client.

OrderManagementFacade.java
package FacadePattern;

public class OrderManagementFacade {
    private ReserveInventory reserveInventory;
    private ReservePayment reservePayment;
    private RefundPayment refundPayment;
    private DeliverySystem deliverySystem;
    private CancelOrder cancelOrder;
 
    public OrderManagementFacade(){
        reserveInventory = new ReserveInventory();
        reservePayment = new ReservePayment();
        refundPayment = new RefundPayment();
        deliverySystem = new DeliverySystem();
        cancelOrder = new CancelOrder();
    }
 
    public void placeOrder(){
        reserveInventory.reserveInventory();
        reservePayment.receivePayment();
        deliverySystem.deliverOrder();
    }
 
    public void cancelOrder(){
        cancelOrder.cancelOrder();
        refundPayment.refundOrderAmount();
    }
}

We will define a client class FacadePatternExample.java which will place and cancel the order using Order Management Facade.

FacadePatternExample.java
public class FacadePatternExample {
    public static void main(String args[]){
        OrderManagementFacade orderingSystem = new OrderManagementFacade();
  
        // Place Order 
        orderingSystem.placeOrder();
        System.out.println("--------------------");
        // Cancel Order 
        orderingSystem.cancelOrder();
    }
}

Output

Blocking Item for Customer.
Deducting amount from customer's credit card.
Deliverying Item to customer's address.
--------------------
Cancelling order.
Refunding Order Amount to Customer.

Best Practices of Facade Design Pattern

To make the most effective use of the Facade Design Pattern, it's essential to follow best practices that contribute to a maintainable and flexible implementation:
  • Design a clear and concise facade interface that hides the complexities of the subsystem from the client. The facade should provide a unified and intuitive interface that meets the client's needs.

  • Provide granular methods in the facade that correspond to specific operations the client might perform. This granularity allows clients to interact with the subsystem at an appropriate level of abstraction.

  • Encourage clients to interact with the subsystem exclusively through the facade. Avoid exposing subsystem components directly to clients, as this can lead to dependencies on specific implementations.

  • Ensure that the facade encapsulates the details of the subsystem and shields the client from the internal structure of individual components. This encapsulation promotes a clean separation of concerns.

  • Handle the initialization and configuration of subsystem components within the facade. This ensures that clients don't need to worry about configuring individual components and can rely on the facade for a simplified setup.

  • Use consistent naming conventions for methods in the facade to enhance code readability. Clear and meaningful names contribute to an understanding of the facade's purpose and functionality.

  • Design the facade and subsystem components to be flexible and extensible. This flexibility allows for the evolution of the subsystem without affecting the facade or requiring changes to client code.

  • Keep the facade focused on providing a simplified interface to the subsystem and avoid introducing business logic within the facade. Business logic should reside in the subsystem components themselves.

  • Clearly document the roles and responsibilities of individual subsystem components. Documentation helps developers understand the purpose and behavior of each component within the subsystem.

Related Topics
Bridge Design Pattern
Mediator Design Pattern
Interpreter Design Pattern
Factory Design Pattern
Prototype Design Pattern
List of Design Patterns