Factory Method Design Pattern with Real-world example

Factory-Method-Design-Pattern-with-Real-world-example

Here you will understand what Factory Method pattern is and you will see how this design pattern helps to solve a real-world problem.

I thought describing it with solving a real-world problem will help you to understand it rather than just describing it. First I’ll describe it using generic explanations and later in this article you can find a real-world example.

What is Factory Method Pattern?

Factory method is one of Creational pattern that uses a factory method to create objects without specifying concrete classes that needs to be created. Confused? Forget it, You will understand all of this down the line.

What Factory method pattern does?

It allows us to create objects by specifying their common interface at run time without imposing their concrete class creation logic.

When to use Factory method pattern?

  1. There should be a set of classes which implement a common interface
  2. You don’t know which object to create ( You know which object to create only at run time)
  3. Object initialization is somewhat expensive(Have to do some operations in order to create an object)

Factory method act as an actual factory. It creates our products which we request but we don’t need to aware of how they are created.

Let’s jump in to the problem.

Imagine you have to develop a system for a bank that allows it’s customers to open Bank accounts and get bank account details. Let’s say initially your application should support creating 3 account types(Personal, Business, and Checking account), and future there may be more account types.

Factory Method Design Pattern - Class hierarchy - UML Diagram

BankAccount interface has few methods that can be overridden by subclasses: validateUserIdentity(), calculateInterestRate() and registerAccount(); and one attribute called name.

What happens you have to create each of the above concrete classes based on user input? Imagine this is a branch of the bank and we have to create accounts based on user requirements.

If user input is P -> Create PersaonAccount object.

If user input is B -> Create BusinessAccount object.

If user input is C -> Create CheckingAccount object.

Following Branch.java class has openAccount() method which takes user input and creates a bank account based on it.

public class Branch {
    public BankAccount openAccount(String type) {
        BankAccount bankAccount = null;
        if (type.equals("P")){
            bankAccount = new PersonalAccount();
        } else if (type.equals("B")){
            bankAccount = new BusinessAccount();
        } else if (type.equals("C")){
            bankAccount = new CheckingAccount();
        } else {
            System.out.println("Invalid type");
        }

        bankAccount.validateUserIdentity();
        bankAccount.calculateInterestRate();
        bankAccount.registerAccount();

        return bankAccount;
    }
}

Then we can call it from our Main method to check whether it is working.

public class Main {

    public static void main(String[] args) {

        BankAccount bankAccount = null;

        Scanner in = new Scanner(System.in);

        System.out.println("Please enter\n" +
                        " P for Personal account\n" +
                        " B for Business account\n" +
                        " C for Checking account\n" +
                "----------------------------");

        String type = in.nextLine();

        Branch branch = new Branch();
        bankAccount = branch.openAccount(type);
    }

}

Event the above code is working fine, directly we can identify three drawbacks.

The first one is, what happens if we have some other places in our code to do the same. Then we have to repeat the above if-else statement in all of those places.

Then the second issue is, what happens if we have to introduce some new bank accounts other than above 3. Then we have to modify our client in this case our openAccount method in the Branch and all other places in order to accommodate new account types.

The third issue is our Branch class is tightly coupled with all the bank account type concrete classes. If bank account types increased later, then there are a number of dependencies for our Branch.

The factory method design pattern addresses all the above issues. What we have to do is create a class called BankAccountFactory and move all the if-else statements which are object creation logic to a single place.

public class BankAccountFactory {
    public BankAccount createAccount(String type){
        BankAccount bankAccount = null;
        if (type.equals("P")){
            bankAccount = new PersonalAccount();
        } else if (type.equals("B")){
            bankAccount = new BusinessAccount();
        } else if (type.equals("C")){
            bankAccount = new CheckingAccount();
        } else {
            System.out.println("Invalid type");
        }
        return bankAccount;
    }
}

Then we have to improve our Branch to use this factory.

public class Branch {

    private BankAccountFactory bankAccountFactory;

    public Branch(BankAccountFactory bankAccountFactory){
        this.bankAccountFactory = bankAccountFactory;
    }

    public BankAccount openAccount(String type) {
        BankAccount bankAccount = null;
        bankAccount = bankAccountFactory.createAccount(type);
        bankAccount.validateUserIdentity();
        bankAccount.calculateInterestRate();
        bankAccount.registerAccount();

        return bankAccount;
    }
}

We have to inject BankAccountFactory to Branch constructor and using that factory createBankAccount method will get it bank account object created. Here you have to understand that our Branch don’t know how those accounts create, BankAccountFactory will do all of it.

But remember, still we have a problem here. It’s still not The Factory Method Patterns yet. This is called The Simple Factory method. Most of the tutorials people teach Simple Factory pattern as Factory method patterns. But we have to improve this Simple Factory pattern in order to fully encapsulated the object generation part so then we call it Factory Method Pattern.

UML Diagram for Simple Factory Pattern.

Factory Method Design Pattern - UML Class diagram for Simple Factory Pattern
Simple Factory Method

The problem here is we cannot further customize our factory. For example, we have to open a new branch in a foreign country so there we have to have some special requirements when creating a BankAccount. If we create our factory which is BankAccountFactory abstract and make LocalBankAccountFactory and ForeignBankAccountFactory as two separate factories which extend abstract BankAccountFactory.

Now we can inject either of factory to the Branch.

        Branch localBranch = new Branch(new LocalBankAccountFactory());
        bankAccount = localBranch.createBankAccount(type);

        Branch foreignBranch = new Branch(new ForeignBankAccountFactory());
        bankAccount = foreignBranch.createBankAccount(type);

Now we can call it Factory Method Design Pattern.

UML Diagram – Factory Method Design Pattern

Factory Method Design Pattern - Full UML Diagram - Real world example
Factory Method Design Pattern

Main class can improve to get two inputs: one for account type and the other one for branch.

public class Main {

    public static void main(String[] args) {

        BankAccount bankAccount = null;

        Scanner in = new Scanner(System.in);

        System.out.println("Please enter\n" +
                        " P for Personal account\n" +
                        " B for Business account\n" +
                        " C for Checking account\n" +
                "----------------------------");

        String type = in.nextLine();

        Scanner inputBranch = new Scanner(System.in);

        System.out.println("Please enter\n" +
                " 1 for Local\n" +
                " 2 for Foreign\n" +
                "----------------------------");

        int branch = inputBranch.nextInt();

     if (branch == 1) {
         Branch localBranch = new Branch(new LocalBankAccountFactory());
         bankAccount = localBranch.createBankAccount(type);
     } else if (branch == 2) {
         Branch foreignBranch = new Branch(new ForeignBankAccountFactory());
         bankAccount = foreignBranch.createBankAccount(type);
        }
    }

}

I hope now you understand the Factory method pattern. Also please download and run the code sample from Github.

If you have any question or suggestion please ask in the comment section.

Also please read this article. It describes about all GoF design patterns that you need to learn.

Source code : https://github.com/Prasadct/design-patterns

35 thoughts on “Factory Method Design Pattern with Real-world example

  1. My relatives always say that I am wasting my time here at net, however I know I am getting familiarity everyday by reading thes fastidious content. Dedie Hubey Marutani

  2. Hello. This article was extremely interesting, especially because I was browsing for thoughts on this subject last couple of days. Nanete Garey Georg

  3. I got this web page from my friend who told me regarding this site and at the moment this time I am browsing this web page and
    reading very informative content here.

  4. great post, very informative. I wonder why the other experts of this sector do not notice this. You should continue your writing. I am sure, you’ve a huge readers’ base already!

Leave a Reply

Your email address will not be published.