The Factory design pattern is a part of the creational design pattern. It works on the concept of Encapsulation by hiding the object’s instantiation logic from the client.
The factory Design pattern is the second most used design pattern in the creational patterns category, after the singleton pattern. The factory pattern is just opposite to the concept of the singleton pattern.
This design pattern doesn’t expose the creation logic of objects to the client. This is done by defining the object creation logic to the subclasses. The factory only shows the common interface which is visible to the clients and works as a contract for how things will get implemented in the framework.
The Java library uses the factory pattern extensively. For example java.util.Calendar
, NumberFormat.getInstance()
and BorderFactory
class of Swing API.
When to use the Factory Design Pattern?
- When there is a need to implement encapsulation. The factory pattern helps to achieve the loose coupling between the objects.
- In a situation when the parent class is responsible to delegate the correct object creation to its subclass with the provided data.
- Such situations when the main application should be unaware of the runtime object creation. This object creation logic is hidden with the help of the layer of interfaces or abstract classes. Then Factory class can be introduced to support object instantiation by using abstract methods.
- When there is a need for a system that is completely independent with the object creation procedures.
Example and Use-case of Factory Design Pattern.
Let us take an example of the most common daily life use-case from online shopping. Suppose one of the eCommerce stores is selling a combo offers for men’s clothing which are Office combo, Casula combo, and Casual Office Combo. It consists of different products as per the categories. Now here factory pattern solves the problem by initiating the objects as per the combo selected by the user.
Below is the practical example of implementing the above scenario in Java by using the Factory Pattern.
The Combo.java shown below is an abstract class. It has abstract methods mainly the products which will be added to the combo offers.
package jstobigdata.designpatterns.factory; public abstract class Combo { public abstract void shirt(); public abstract void trousers(); public abstract void shoes(); }
Now let’s say we need OfficeCombo. So we create a subclass OfficeCombo.java which extends the abstract class Combo.java
, This subclass overrides the abstract methods by putting the main logic for Office Combo products.
package jstobigdata.designpatterns.factory; public class OfficeCombo extends Combo { @Override public void shirt() { System.out.println("Add Shirt into the cart from office category."); } @Override public void trousers() { System.out.println("Add trouser into the cart from office category."); } @Override public void shoes() { System.out.println("Add shoes into the cart form office category"); } }
Similar to OfficeCombo, if you want to offer CasualCombo, just create a subclass that extends the abstract class Combo.java. This subclass overrides the abstract methods by putting the main logic for Casual Combo products.
package jstobigdata.designpatterns.factory; public class CasualCombo extends Combo { @Override public void shirt() { System.out.println("Add Shirt into the cart from casual category."); } @Override public void trousers() { System.out.println("Add trouser into the cart from casual category."); } @Override public void shoes() { System.out.println("Add shoes into the cart form casual category"); } }
Again, if you have to offer a new set of a combo like CasualOffice Combo products. This can be easily done as below.
package jstobigdata.designpatterns.factory; public class CasualOfficeCombo extends Combo { @Override public void shirt() { System.out.println("Add Shirt into the cart from common category."); } @Override public void trousers() { System.out.println("Add trouser into the cart from common category."); } @Override public void shoes() { System.out.println("Add shoes into the cart form common category"); } }
The above class is again an abstract class in which there is an abstract method implemented createCombo()
which is having an argument of the String type, this will be the name of the combo which the user will pass from the concrete class(Client).
package jstobigdata.designpatterns.factory; public abstract class BasicCombo { public abstract Combo createCombo(String comboype); }
Now we will write the actual factory code that will create the actual combo
objects.
package jstobigdata.designpatterns.factory; public class ComboCreationLogic extends BasicCombo { @Override public Combo createCombo(String comboype) { Combo combo; switch (comboype) { case "office": combo = new OfficeCombo(); break; case "casual": combo = new CasualCombo(); break; case "casualoffice": combo = new CasualOfficeCombo(); break; default: throw new IllegalArgumentException("No such product exitsts."); } combo.shirt(); combo.trousers(); combo.shoes(); return combo; } }
The above class is a subclass which is extending the abstract class Basiccombo
, In this class, we have overridden the method `createCombo()
and by applying a switch we are generating the objects as per the condition provided by the user.
package jstobigdata.designpatterns.factory; public class TestingFactoryPattern { public static void main(String[] args) { BasicCombo comboplan = new ComboCreationLogic(); Combo officecombo = comboplan.createCombo("office"); Combo casualcombo = comboplan.createCombo("casual"); Combo officecasualcombo = comboplan.createCombo("casualoffice"); } }
Above is the main class which is basically a testing class for the classes written above. In this, we are creating an object of Combo.java
and using this object we are calling all the createCombo()
with different parameters.