Mastering Factory Design Patterns through the Construction of a Banking System
Published: 2023-01-31 01:39:35

First of all, let's define the

### Requirements of our problem

* There can be multiple banks
    
    * All banks **share some common attributes and behavior** like
        
        * Behavior - `showBalance()` , `withdraw()` , `addBalance()` etc
            
        * Attributes - `amount_left` , `num_of_users` etc.
            
    * Banks can also implement their unique methods and attributes
        
* Provide a simple interface to the user for creating `bank` objects of their choice (i.e., users should now be responsible for)
    
* **Our solution should follow S.O.L.I.D. Principle**
    

### Having Multiple Banks

Let's start by defining two banks classes - `A1` and `A2`

```cpp
class A1 {
    private:
        int amount_left , num_of_users; // .. other params
    public:
        int NumOfUsers(){...} 
        // Other attributes
};

class A2 {
    private:
        int amount_left , num_of_users; // .. other params
    public:
        int NumOfUsers(){...} 
        // other attributes
};
```

Notice something wrong.

* **First of all, there is a ton of code duplication**. Since there are a lot of common attributes and methods we will be writing, the same code again and again.
    
* **Secondly,** there is no guarantee that all classes will define the common attributes and methods.
    

To solve these issues, we can define a **common interface.** This **common interface** will have all common attributes and methods. All other classes that **implement** this **common interface** will have to define the methods.

* It solves the code duplication part, as we don't need to redefine the attributes and methods in the subclasses. (**classes that implement the interface**)
    
* Any class that implements the common interface needs to define the methods.
    

Let's have a look at the code now.

```cpp
class Bank{
    protected:
        int amount_left , num_of_users; // .. other common attributes
    public:
        virtual int NumOfUsers(){ // Subclass can redefine this
            return this->num_of_users
        } 
        virtual int getBalance() const = 0; //Subclass have to redefine this
};

class A1 : public Bank {
    private:
        int special_params;
    public:
       int getBalance() const override{...}
};

class A2 : public Bank {
    private:
        int special_params;
    public:
       int getBalance() const override{...}
};
```

Okay, now that this is taken care of, let's focus on the second requirement.

### Provide a simple interface to the user for creating `a bank` objects of their choice

In our existing code, if a user wants to create a bank object then

```cpp
void client(){
    A1* a1 = new A1;
    std::cout<<a1->getBalance(); 
}
```

Well, this doesn't look that bad, but we are exposing too much of our backend logic to the client. Ideally, the client shouldn't know about every subclass. We should be providing a centralized code for bank selection. Let's define a new class for this.

```cpp
class BankCreator{
    Bank* getBankInstance(string bankName){
        switch(bankName){
            case "a1":
                return new A1;
            case "a2":
                return new A2;
            default:
                return NULL;
        }
    }
};

void client(){
    BankCreator* backCreator = new BankCreator;
    Bank* a1 = backCreator->getBankInstance("a1");
    Bank* a2 = backCreator->getBankInstance("a2");
}
```

> **NOTE:** All the objects created by the `BankCreator` class should have a common superclass.

Now, this looks great. But do you notice something wrong with our code?

The `BankCreator` class violates the **<mark>Open For Extension and Closed for Modification Principle.</mark>**

When we are adding a new bank (subclass) we need to modify the `BankCreator` class (add another case to the switch statement).

So, we need to define the creator class in such a way that whenever we add/remove a bank subclass, we do so without modifying the creator class. To do this

* We first make the creator a class an interface
    
* ```cpp
         class BankCreator{
          protected:
              virtual Bank* getBankInstance() const = 0;
      };
    ```
    
* Now to add a new `bank` we simply implement this interface
    
* ```cpp
      class A1Creator: public BankCreator{
          Bank* getBankInstance() const override{
              return new A1;
          }
      };
      
      class A2Creator: public BankCreator{
          Bank* getBankInstance() const override{
              return new A2;
          }
      };
    ```
    
    Since we can add new bank subclasses without modifying the creator class, we can say that we are following the **<mark>Open For Extension and Closed for Modification Principle.</mark>**
    

Now a client can create a bank object in the following way

```cpp
void client(){
    A1Creator* a1creator = new A1Creator;
    A1* a1 = a1creator->getBankInstance();
    A1* a11 = a1creator->getBankInstance();
}
```

> Also, it might look like we are exposing too much of our backend logic, but that's not the case. The client is not concerned about the implementation of the concrete subclasses (`bank subclasses`) but is only aware of creator classes.

Before moving forward, here's the entire

### Pseudo code for Factory Design Pattern

```cpp
//This is an Abstract class. But you can also make it an interface 
class Bank{
    protected:
        int amount_left , num_of_users; // .. other common attributes
    public:
        virtual int NumOfUsers(){ // Subclass can redefine this
            return this->num_of_users
        } 
        virtual int getBalance() const = 0; //Subclass have to redefine this
};

class A1 : public Bank {
    private:
        int special_params;
    public:
       int getBalance() const override{...}
};

class A2 : public Bank {
    private:
        int special_params;
    public:
       int getBalance() const override{...}
};

class BankCreator{
      protected:
          virtual Bank* getBankInstance() const = 0;
};

 class A1Creator: public BankCreator{
      Bank* getBankInstance() const override{
          return new A1;
      }
  };
  
  class A2Creator: public BankCreator{
      Bank* getBankInstance() const override{
          return new A2;
      }
  };

void client(){
    A1Creator* a1creator = new A1Creator;
    A1* a1 = a1creator->getBankInstance();
    A1* a11 = a1creator->getBankInstance();
}
```

Now, let's discuss the pros and cons of this pattern

## ✅ Pros

* It follows the <mark> Single Responsibility Principle.</mark>
    
    The `creator` class and each `concrete creator` subclass have only one responsibility. Tldr, there is a segregation of responsibility.
    
* It follows the **<mark>Open For Extension and Closed for Modification Principle.</mark>**
    
* There is **<mark>loose coupling</mark>**
    
    Instead of adding the logic to decide the type of object in the `creator` class, we are assigning the responsibility to some other class
    

## ❌ Cons

* Code can become **<mark>too complex.</mark>**
    
    Since we are adding a lot of subclasses.
    

---

Cover image credit: [Image by storyset](https://www.freepik.com/free-vector/factory-concept-illustration_12892954.htm#query=factory&position=0&from_view=keyword) on Freepik