In this article, we will try to implement a Facade Design pattern using an example of a banking system that has different types of accounts like checking and savings.

Q. What is the Goal/Purpose of the Facade Pattern with analogy?

The goal is to provide a single simplified interface for client classes to interact with the sub-system while hiding complexity from the client side. In our example, we will be using the information hiding principle to prevent all client classes from seeing the account type objects in our simple banking system and how these accounts behave.

Q. What is Facade and why is it used?

Facade is simply a point of entry into any subsystem; e.g., a waiter at a restaurant while ordering food, an online shopping portal for ordering products, shipping, production etc.

Q. How would client code interact with the subsystem without a façade class for our simple banking system?

Q. How would client code interact with the subsystem with a façade class for our simple banking system?

Q. How do we Implement a Facade Pattern for our Example?

Step 1. Implementing our BankService facade class which wraps the other classes that implement the interface.

public class BankService {
    private Dictionary<int, IAccount> bankAccounts;

    public BankService() {
        bankAccounts = new Dictionary<int, IAccount>();
    }

    public int createNewAccount(string type, BigInteger initAmount) {
        IAccount newAccount = null;

        switch (type) {
            case "chequing":
                newAccount = new Chequing(initAmount);
                break;
            case "saving":
                newAccount = new Saving(initAmount);
                break;
            case "investment":
                newAccount = new Investment(initAmount);
                break;
            default:
                Console.WriteLine("Invalid account type");
                break;
        }

        if (newAccount != null) {
            bankAccounts.Add(newAccount.getAccountNumber(), newAccount);
            return newAccount.getAccountNumber();
        }
        return -1;
    }

    public void transferMoney(int to, int from, BigInteger amount) {
        IAccount toAccount = GetAccount(bankAccounts, to);
        IAccount fromAccount = GetAccount(bankAccounts, from);

        if (toAccount != null && fromAccount != null) {
            fromAccount.transfer(toAccount, amount);
        } else {
            // we can inform user about failure either by throwing exception or sending error code.
        }
    }

    // we can replace below searching account code with any other efficient code as per requirement.
    private IAccount GetAccount(Dictionary<int, IAccount> bankAccounts, int to) {
        IAccount account = null;
        if (bankAccounts.TryGetValue(to, out account)) {
            return account;
        }
        return account;
    }
}

From the above code snippet we can observe.

Step 2. Implementing Customer class which uses BankService facade class to access the subsystem.

public class Customer
{
    static void Main(string[] args)
    {
        BankService bankService = new BankService();
        int savingAccount = bankService.createNewAccount("saving", new BigInteger(500.00));
        int investmentAccount = bankService.createNewAccount("investment", new BigInteger(1000.00));
        bankService.transferMoney(savingAccount, investmentAccount, new BigInteger(300.00));
    }
}

From the above code snippet we can observe.

Q. Advantages of Facade Design Pattern?

  1. This pattern hides the complexity of a subsystem by encapsulating it behind a unifying wrapper called a Facade class.
  2. Removes the need for client classes to manage a subsystem on their own, resulting in less coupling between the subsystem and the client classes.
  3. Handles instantiation and redirection tasks to the appropriate class within the subsystem.
  4. Provides client classes with a simplified interface for the subsystem.
  5. Acts as a point of entry to a subsystem and does not add more functionality to the subsystem.