Facade Design Pattern

The Facade Design Pattern is a simplified interface to a subset of a complex existing system. The intended use case of the Facade Design Pattern is to...

The Facade Design Pattern is a simplified interface to a subset of a complex existing system. The intended use case of the Facade Design Pattern is to shield the user from intricate implementation details of a system while providing the user with a clear and concise set of functionalities through an interface.

Provide a unified interface to a set of interfaces in a subsystem. Facade defines higher-level interfaces that make the subsystem easier to use

Related definitions

Before we dig deep into a Facade design pattern, here are some definitions related to Facade design patterns

Facade

  • Knows which subsystem classes are responsible for a request
  • Delegates client requests to appropriate subsystem objects.

Subsystem Classes

  • Implements subsystem functionality.
  • handles work assigned by the Facade object.
  • have no knowledge of the facade; they keep no reference to it.

Problem

Let’s say that we need to develop a compiler for a brand new programming language.

The compiling process consists of scanning, tokenizing, parsing, building an abstract syntax tree, code generation, etc. We need to develop a separate subcomponent for each step. In principle, each subcomponent is complex, and the usage of subcomponents is also tricky.

It does not make sense for a client who wants to compile code to invoke complex subcomponents to compile.

A better approach would be to define a uniform interface that presents the compiler functionality – a Compiler class. The Compiler class hides “low-level” functionality from the client, so we can say that the Compiler class is a facade.

The Facade design pattern hides the complexity of a system and provides an interface to the client through which the client can access the system.

Facade Design Pattern

Pros and cons of facade design pattern

Pros

  • It shields clients from subsystem components, thereby reducing the number of objects that clients deal with and making the subsystem easier to use.
  • The components of the complex subsystem can be upgraded/changed without affecting the client. The client usually has one friend: The facade class, which follows the principle of least knowledge. In OO programming, having only one friend is a good thing.
  • It doesn’t prevent applications from using subsystem classes if needed.

Cons

  • Clients cannot access underlying classes, and certain functionalities might be unavailable to clients
  • It usually does not add any extra functionalities, just simplifying it for the clients to use

Benefits of facade design pattern

Use the facade pattern when

  • you want to provide a simple interface to a complex subsystem.
  • To decouple a subsystem from clients and other subsystems, thereby promoting system independence and portability.
  • To define an entry point to each subsystem level. If subsystems are dependent, then the dependencies can be simplified by making them communicate with each other solely through their façade.

Facade design pattern example

Let’s assume you are building the module within the e-commerce application that deals with placing orders. When the user selects a product. and press a buy button; there are several steps to place an order within an e-commerce application

  • User Service: Authenticate the user.
  • Product Service: Verify the product’s availability.
  • Product Service: Assign product to the user.
  • Payment Service: Make Payment.
  • Notification Service: Send Notification to the dealer.

If you were to integrate all the above systems and services on the button click, it would hamper the code’s readability. And would also make it a nightmare for maintainability (in case you want to change the underlying system). The code below is for the implementation of subsystems.

public class NotificationService implements Services{
    public static void notifyDealer(String productId){
        System.out.println("[NotificationService] notifying"+
                           "dealer about the sale of the product "+productId);
//        complex notification logic
    }
}

public class PaymentService implements Services{
    public static void makePayment(String userId, String productId){
        System.out.println("[PaymentService]charging user "
                           +userId+" for product "+productId);
//        complex logic for making payment
    }
}

public class ProductService{
    static void assignProductToUser(String productId, String userId){
//        complex code for product assignment
        System.out.println("[ProductService]assigning "+productId
                           +" to user "+userId);
    }
    static boolean isProductAvailable(String productId){
//        complex code for checking product availability
        System.out.println("[ProductService]checking availability of "
                           +productId);
        return true;
    }
}
public class UserService implements Services{
    @Override
    public static boolean isUserValid(String userId){
        System.out.println("[UserService]validating user ID, "+userId);
//        complex code for checking product availability
        return true;
    }
}
public class Facade {
    static UserService userService;
    static ProductService productService;
    static PaymentService paymentService;
    static NotificationService notificationService;

    public static void placeOrder(String userId, String productId){
        System.out.println("[facade]starting order placement");
        boolean userValid = userService.isUserValid(userId);
        boolean productAvailable = ProductService.isProductAvailable(productId);

        if (userValid==true && productAvailable==true){
            productService.assignProductToUser(productId, userId);
            paymentService.makePayment(userId, productId);
            notificationService.notifyDealer(productId);
        }
    }
}

When the user wants to place an order for a new product, all he needs to do is create an object of facade type and use the place order method. All the implementation details are hidden from the client.

public class Main {

    public static void main(String[] args) {
	    Facade facade = new Facade();
        facade.placeOrder("testUser", "dummyProduct");
    }
}

Related Articles