Link Search Menu Expand Document

The Facade Design Pattern

The Facade Pattern is designed to hide an entire subsystem behind a facade and present is as a single object/ interface.


What problems does it solve?

Provides simple facade for the client and hides the complexity of the implementation just like the “face of a building”. Clients can see only outside, they do not what’s inside.

Pros:

  • Provides high level of isolation
  • Hides complexity and makes system easier to use
  • Reduces dependencies between components/ subsystems

Cons:

  • Larger API
  • May hide important information as useless information

How to recognize it?

When you call behavioral methods, which internally use instances of different independent abstract/interface types.

Examples from Java API

JDBC driver uses facade to hide complexity of getting connection to different database servers (Oracle, MySql, etc)
javax.faces.context.FacesContext, it internally uses among others the abstract/interface types LifeCycle, ViewHandler, NavigationHandler 
and many more without that the enduser has to worry about it (which are however overrideable by injection).
javax.faces.context.ExternalContext, which internally uses ServletContext, HttpSession, HttpServletRequest, HttpServletResponse, etc.

Scenarios

  • To divide a system into multiple subsystems, that doesn’t know much about the complexity of the subsystems they interact with.
  • JDBC driver uses facade to hide complexity of creating connection to different database servers.

Example 1

We (as customers) want a single pay desk service or mobile app, where we can pay all our bills no matter which provider we use. In this case we need a Payment Service Facade, that we can use to pay our bills. The facade will introduce very simple interface. What’s hidden inside is, that each provider has it’s own payment service, where we should submit each payment.

Source Code

1). Create the Facade - we will accept payments for four different providers

public interface PaymentServicesFacade {

    void payPhoneBill(String billNo);

    void payElectricityBill(String billNo);

    void payGasBillToProvider1(String billNo);

    void payGasBillToProvider2(String billNo);
}

2). Create separate interface for each provider

public class ElectricityPaymentSystem {

    public void pay(Customer customer, String billNo) {
        System.out.println("Payment for billNo= " + billNo + " from " + customer.getName() + " received by the electricity provider.");
    }
}
public class GasOnlinePaymentServices {

    public void payBill(Customer customer, String billNo) {
        System.out.println("Payment for billNo= " + billNo + " from " + customer.getName() + " received by the gas provider 1.");
    }
}
public class SuperGasPaymentProvider {

    public void payBill(Customer customer, String billNo) {
        System.out.println("Payment for billNo= " + billNo + " from " + customer.getName() + " received by the gas provider 2.");
    }
}
public class TelecommOnlinePayDesk {

    public void payPhoneBill(Customer customer, String billNo) {
        System.out.println("Payment for billNo= " + billNo + " from " + customer.getName() + " received by the mobile services provider.");
    }
}

3). Now we want to implement the facade

public class PaymentServicesFacadeImpl implements PaymentServicesFacade {

    @Getter
    private Customer customer;

    public PaymentServicesFacadeImpl(Customer customer) {
        this.customer = customer;
    }

    @Override
    public void payPhoneBill(String bill) {
        TelecommOnlinePayDesk onlinePayDesk = new TelecommOnlinePayDesk();
        onlinePayDesk.payPhoneBill(getCustomer(), bill);
    }

    @Override
    public void payElectricityBill(String bill) {
        ElectricityPaymentSystem paymentSystem = new ElectricityPaymentSystem();
        paymentSystem.pay(getCustomer(), bill);
    }

    @Override
    public void payGasBillToProvider1(String bill) {
        GasOnlinePaymentServices paymentServices = new GasOnlinePaymentServices();
        paymentServices.payBill(getCustomer(), bill);
    }

    @Override
    public void payGasBillToProvider2(String bill) {
        SuperGasPaymentProvider paymentServices = new SuperGasPaymentProvider();
        paymentServices.payBill(getCustomer(), bill);
    }
}

4). Run the demo

public class _Main {

    public static void main(String[] args) {
        // Jon Snow
        PaymentServicesFacade paymentServices1 = new PaymentServicesFacadeImpl(new Customer("Jon Snow"));
        paymentServices1.payElectricityBill("BN123/20");
        paymentServices1.payGasBillToProvider2("233834esd4rcWQWFG3");
        paymentServices1.payElectricityBill("122398");
        
        System.out.println("");

        // Alice Young
        PaymentServicesFacade paymentServices2 = new PaymentServicesFacadeImpl(new Customer("Alice Young"));
        paymentServices2.payGasBillToProvider1("ACVVVS");
    }
}

Output:

Payment for billNo= BN123/20 from Jon Snow received by the electricity provider.
Payment for billNo= 233834esd4rcWQWFG3 from Jon Snow received by the gas provider 2.
Payment for billNo= 122398 from Jon Snow received by the electricity provider.

Payment for billNo= ACVVVS from Alice Young received by the gas provider 1.