GOF Factory – Have your own too

Factory Pattern is another creational pattern. As the name implies, we create a kind of Factory class in it. In general terminology, factory is the place where some kind of products are manufactured.  In software terminology, factory class is a class that manufactures objects. So the object creation task is the main responsibility of Factory class.

Now you may be thinking, we have a very good ‘new’ operator with which we can easily create new objects. So why to have a class in between?

You are right.

Factory pattern should be used only in specific situations as I will explain below.

One way to understand a pattern is to find out the limitations we will be facing by not using it. Here is an example:

e.g. Suppose a new bank opens which offers Saving accounts only to its customers. Normally the information a customer needs from his saving account is following;

a) Balance Enquiry
b) Withdraw amount
c) Deposit amount

so following class will be sufficient

public class SavingAccount
{
      private String accountNumber;

      //constructor
      SavingAccount(String accountNumber)
      {
            this.accountNumber = accountNumber;

      }

      public float getBalance()
      {
            /*
            balance retrieval and return
            */
      }

      public float debitAccount(float amount)
      {
            /*
            subtract amount from balance in database and return updated balance
            */
      }

      public float creditAccount(float amount)
      {
            /*
            add amount in balance in database and return updated balance
            */
      }
}

Also bank has a website for customers. Customers select their account type from the drop down provided (currently only Saving is available), enter their account number and are presented with the information they need.

Client class will be something like below (for simplicity I have put only 1 method in it):

public class Client
{
      public void processAccount(String accountType, String
accountNumber)
      {
            //no need to use accountType because only saving is
available
            SavingAccount sa = new SavingAccount(accountNumber);
            float balance = sa.getBalance();
            float updatedBalance = sa.debitAccount(59.50);
      }
}

Now suppose after 6 months Bank starts to offer Current Account also. Current account also offers same kind of facilities i.e.:

a) Balance Enquiry
b) Withdraw amount
c) Deposit amount

How will you proceed?
One way is to have a class specific to Current Account as follows:

public class CurrentAccount
{
      private String accountNumber;

      //constructor
      CurrentAccount(String accountNumber)
      {
            this.accountNumber = accountNumber;

      }

      public float getBalance()
      {
            /*
            balance retrieval and return
            */
      }

      public float debitAccount(float amount)
      {
            /*
            subtract amount from balance in database and return updated balance
            */
      }

      public float creditAccount(float amount)
      {
            /*
            add amount in balance in database and return updated balance
            */
      }
}

In UI,  2 options are provided in dropdown now (saving and current)

Do you need to modify client? Definitely. How will you modify, here’s it

public class Client
{
      public void processAccount(String accountType, String
accountNumber)
      {
            if (accountType.equalsIgnoreCase("saving"))
            {
                  SavingAccount sa = new
SavingAccount(accountNumber);
                  float balance = sa.getBalance();
                  float updatedBalance = sa.debitAccount(59.50);
            }
            else if (accountType.equalsIgnoreCase("current"))
            {
                  CurrentAccount ca = new
CurrentAccount(accountNumber);
                  float balance = ca.getBalance();
                  float updatedBalance = ca.debitAccount(59.50);
            }
      }
}

Hmmm, that’s OK but here are some points to be noted:

1. CurrentAccount and SavingAccount classes are having same methods. And it is also possible that code within some methods is exactly same. Still we are duplicating this code.
2. Although statements in each if block of client code are similar, but we have to write them again and again for each account type.
3. What if a new account type comes in to picture tomorrow? You will have to update Client again. WHAT IF YOU HAVE 10 SUCH CLIENTS?

Above points lead to the conclusion that enhancement and maintenance of above code is not simple. Especially, assume of a project having 100 classes where many classes are having similar methods and there are a lot of clients of these classes.

Factory Pattern comes to rescue here.

Here’re the changes we will make:

1. Since CurrentAccount and SavingAccount classes are having same
methods so let’s have a parent class on top of these as below

public class Account
{
      private String accountNumber;

      //constructor
      Account(String accountNumber)
      {
            this.accountNumber = accountNumber;

      }

      public float getBalance()
      {
            /*
            balance retrieval and return
            */
      }

      public float debitAccount(float amount)
      {
            /*
            subtract amount from balance in database and return updated balance
            */
      }

      public float creditAccount(float amount)
      {
            /*
            add amount in balance in database and return updated balance
            */
      }
}

And let CurrentAccount and SavingAccount classes extend it (inherit from it for C++ friends)

public class SavingAccount extends Account
{
      private String accountNumber;

      //constructor
      SavingAccount(String accountNumber)
      {
            super(accountNumber);
            this.accountNumber = accountNumber;

      }

      /*
      You can override getBalance(), debitAccount() and creditAccount() methods here IF LOGIC OF THESE WILL BE SPECIFIC TO THIS CLASS
      */
}

public class CurrentAccount extends Account
{
      private String accountNumber;

      //constructor
      CurrentAccount(String accountNumber)
      {
            super(accountNumber);
            this.accountNumber = accountNumber;

      }

      /*
      You can override getBalance(), debitAccount() and creditAccount() methods here IF LOGIC OF THESE WILL BE SPECIFIC TO THIS CLASS
      */
}

so we have reduced a lot of code. That feels good…isn’t it?

2. Now let’s clean up Client class. If we think over it, we will find that all issues in Client class are because it needs to judge which type of object it has to create. So let’s take that code out of it.

public class Client
{
      public void processAccount(String accountType, String
accountNumber)
      {
            Account account = AccountFactory.getAccount(accountType,
accountNumber);
            float balance = account.getBalance();
            float updatedBalance = account.debitAccount(59.50);
      }
}

Hmm what a simple code it has become, looks GREAT!! What do you feel????

And you know, it is general too…so if a new client class comes in to picture tomorrow with same methods this code will still work without change (we will talk abt methods specific to a class too).

Now the question is what is this "AccountFactory" thing on first statement in Client class i.e.           

Account account = AccountFactory.getAccount(accountType,
accountNumber);

Friends, it is a factory class which will manufacture objects for us.
Here’s how:

public class AccountFactory
{
      private AccountFactory()
      {
      }

      public static Account getAccount(String accountType, String
accountNumber)
      {
            Account account = new SavingAccount(accountNumber);

            if (accountType.equalsIgnoreCase("current"))
            {
                  account = new CurrentAccount(accountNumber);
            }

            return account;
      }
}

So it all looks better now. If tomorrow a new Account type comes in to picture having similar methods, we will create a new class (extending Account of course), and change only 1 more class i.e. AccountFactory even if we have 100 clients using our classes.

So that Factory pattern for you.

Some points to be noted:

1. Make Factory class singleton because you will not need to create multiple instances of it
2. If each method is specific to child class, make Account an interface instead of a class
3. If some methods are general make Account a class, and put the definition there (as we have done). But if you don’t want the instantiation of Account class, make it abstract
4. If you are sure that you have only a single class (like we had SavingAccount at the start) at hand and more similar classes will not come in to picture in future don’t go for Factory pattern. It will unnecessarily add a layer and will impact the performance.
5. If you have some methods specific to a child class, there are 2 approaches:
      a) Put the method in Child class itself
      b) Put all methods in Base class with default implementation for.e.g. If CurrentAccount allows overDraft also which SavingAccount
does not allow, following code will work acc. to approach a) and b) respectively

a) Put the method in Child class itself

Put overDraft() method in CurrentAccount Class

public class CurrentAccount extends Account
{
      private String accountNumber;

      //constructor
      CurrentAccount(String accountNumber)
      {
            super(accountNumber);
            this.accountNumber = accountNumber;

      }

      /*
      You can override getBalance(), debitAccount() and creditAccount() methods here IF LOGIC OF THESE WILL BE SPECIFIC TO THIS CLASS
      */

      public void overDraft(float amount)
      {
            //method definition
      }
}

and change the client as below

public class Client
{
      public void processAccount(String accountType, String
accountNumber)
      {
            Account account = AccountFactory.getAccount(accountType,
accountNumber);
            float balance = account.getBalance();
            float updatedBalance = account.debitAccount(59.50);

            if (account instanceof CurrentAccount)
            {
                  //cast and then call method
                  ((CurrentAccount)account).overDraft(23.50f);
            }
      }
}

b) Put all methods in Base class with default implementation

Put the overDraft() method in Account class itself with default (may be blank) implementation. And let CurrentAccount override it according to its needs. See code below:

public class Account
{
      private String accountNumber;

      //constructor
      Account(String accountNumber)
      {
            this.accountNumber = accountNumber;

      }

      public float getBalance()
      {
            /*
            balance retrieval and return
            */
      }

      public float debitAccount(float amount)
      {
            /*
            subtract amount from balance in database and return updated balance
            */
      }

      public float creditAccount(float amount)
      {
            /*
            add amount in balance in database and return updated balance
            */
      }

      public void overDraft(float amount)
      {
            //method definition – leave it blank
      }

}

public class CurrentAccount extends Account
{
      private String accountNumber;

      //constructor
      CurrentAccount(String accountNumber)
      {
            super(accountNumber);
            this.accountNumber = accountNumber;

      }

      /*
      You can override getBalance(), debitAccount() and creditAccount() methods here IF LOGIC OF THESE WILL BE SPECIFIC TO THIS CLASS
      */

      //overides overDraft method of Account class
      public void overDraft(float amount)
      {
            //method definition
      }
}

and let the client be simple as below:

public class Client
{
      public void processAccount(String accountType, String
accountNumber)
      {
            Account account = AccountFactory.getAccount(accountType,
accountNumber);
            float balance = account.getBalance();
            float updatedBalance = account.debitAccount(59.50);
            account.overDraft(23.50f);
      }
}

That?s Factory pattern friends, hope you enjoyed learning it. One assignment for you:

Assignment – How will you change the Factory class so as to make it generic? That is even if a new Account Type comes into picture tomorrow; still you should not be required to change the Factory class. Think over it.

regards

Varun

The following two tabs change content below.
Content Team

Content Team

The IndicThreads Content Team posts news about the latest and greatest in software development as well as content from IndicThreads' conferences and events. Track us social media @IndicThreads. Stay tuned!
Content Team

Content Team

The IndicThreads Content Team posts news about the latest and greatest in software development as well as content from IndicThreads' conferences and events. Track us social media @IndicThreads. Stay tuned!

  • vjoshi0612@gmail.com
  • varun077

    Thanks Friend.
    I will go in more detail and evaluate what you said.

  • Guest

    😡 doesn’t exist any ‘Factory’ pattern in gof book nor in any other bibliografy, the patterns are ‘ABSTRACT FACTORY’ and ‘FACTORY METHOD’ and your AccountFactory is neither of them, maybe you have to read some more books to understand the differences and their real intent.
    What you are implementing is something similar to a PRODUCT TRADER [Plop ’96] in the silliest form :p