Java Creational Design Patterns – Abstract Factory Pattern
The Abstract Factory Pattern is one of the creational design patterns. We can say Abstract Factory patterns acts as a super-factory which produces other factories. The role of the Abstract Factory is to provide an interface for creating families of related or dependent objects without specifying their concrete classes.
If we are using an abstract factory pattern, then the client program will never create platform objects directly, they ask the factory to perform this task for them. So the factory object has the total responsibility for proving this service for the entire platform family. You can use this pattern if-
- You need your application to be independent of how its objects are created.
- To decouple classes and way its objects are created.
- If your business logic involves families of related or dependent objects.
<Here are ALL Java Design Patterns, explained in detail with examples>
Abstract Factory Pattern by Example
For our understanding of this pattern, we will take a simple example of different types of Bank Accounts. When you are dealing with Bank, for every type of your need there is an account created to track the books. We will try to apply this pattern on account types like Savings, Current, HomeLoan etc.
To start we will define our core interface, which has a single method to show us the interest rate of that account type.
1 2 3 |
public interface Account { public void getInterestRate(); } |
Now, we will define a few concrete classes, that will implement the above interface.
SavingsAccount
1 2 3 4 5 6 7 8 |
public class SavingsAccount implements Account { @Override public void getInterestRate() { System.out.println("Savings Account Interest Rate = 4.0% pa"); } } |
Current Account
1 2 3 4 5 6 7 8 |
public class CurrentAccount implements Account { @Override public void getInterestRate() { System.out.println("Current Account Interest Rate = 5.0% pa"); } } |
Home Loan Account
1 2 3 4 5 6 7 8 |
public class HomeLoan implements Account { @Override public void getInterestRate() { System.out.println("Home Loan Interest Rate = 8.5% pa"); } } |
Education Loan Account
1 2 3 4 5 6 7 8 |
public class EducationLoan implements Account { @Override public void getInterestRate() { System.out.println("Education Loan Interest Rate = 11.5% pa"); } } |
After this, we will define our Abstract Factory abstract class. This class will be extended by different Family Factories such as Account Factory or Loan Factory.
1 2 3 |
public abstract class AbstractFactory { abstract Account getAccount(String type) ; } |
also below are different factories-
LoanFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class LoanFactory extends AbstractFactory { @Override Account getAccount(String type) { Account account = null; if ("Home".equalsIgnoreCase(type)) { account = new HomeLoan(); } else if ("Education".equalsIgnoreCase(type)) { account = new EducationLoan(); } return account; } } |
AccountFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class AccountFactory extends AbstractFactory { @Override Account getAccount(String type) { Account account = null; if ("Savings".equalsIgnoreCase(type)) { account = new SavingsAccount(); } else if ("Current".equalsIgnoreCase(type)) { account = new CurrentAccount(); } return account; } } |
Last but not least we will add a Factory Provider, which is kind of a wrapper or super factory.
1 2 3 4 5 6 7 8 9 10 11 |
public class FactoryProvider { public static AbstractFactory getFactory(String choice) { AbstractFactory af = null; if ("Loan".equalsIgnoreCase(choice)) { af = new LoanFactory(); } else if ("Account".equalsIgnoreCase(choice)) { af = new AccountFactory(); } return af; } } |
Running the Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class AbstractFactoryDemo { public static void main(String[] args) { AbstractFactory lf = FactoryProvider.getFactory("Loan"); Account loan1 = lf.getAccount("Home"); loan1.getInterestRate(); Account loan2 = lf.getAccount("Education"); loan2.getInterestRate(); AbstractFactory af = FactoryProvider.getFactory("Account"); Account account1 = af.getAccount("Savings"); account1.getInterestRate(); Account account2 = af.getAccount("Current"); account2.getInterestRate(); } } |
Output:
1 2 3 4 |
Home Loan Interest Rate = 8.5% pa Education Loan Interest Rate = 11.5% pa Savings Account Interest Rate = 4.0% pa Current Account Interest Rate = 5.0% pa |
Conclusion
In this article, we understood the Abstract Factory Pattern with the help of a simple example. While the pattern is great when creating predefined objects and providing abstraction, a new addition of object family might be difficult. To support the new type of objects will require changing the AbstractFactory class and all of its subclasses.
The source code is available in our Github repository.
Download Code<Here are ALL Java Design Patterns, explained in detail with examples>