Factory design pattern

Factory Design Pattern is part of a creational design pattern like a singleton design pattern. These patterns provide one of the best ways to create an object. Here we will learn about it and see why it is useful to develop a project. It is widely used in JDK as well as frameworks like Spring and Struts.

Here is the table content of the article will we will cover this topic.
1. Factory design pattern?
2. Why do we use factory pattern java?
3. Factory design pattern in java with real-time example?
4. Factory design pattern advantages?
5. Factory Design Pattern Examples in JDK?

Factory design pattern

The Factory pattern is used to create an object without exposing the creation logic to the client and it creates the new object from a common interface. The factory design pattern in java

The factory design pattern is useful when we have an interface (Java interface or abstract class) and multiple sub-classes. We can create an object of subclasses based on input.  The factory design pattern says just define an interface or an abstract class and the subclasses will decide which object should be created. It means subclasses will be responsible to create the object of the class according to the use of the object. The factory provides a method known as the Factory method and it allows a class to defer instantiation to subclasses. This Factory Method Pattern is also known as Virtual Constructor.

Before moving further, we need to understand the problem statement. We should know the use case of the factory pattern and why we use it?  What type of problem we are facing without a factory pattern?

Why do we use factory pattern java?

When we develop an application or project, we write a huge code that maybe leads to coupling problems. When the code gets larger, we face real-time problems. If a class needs any extra feature, then we figure all the code where we are using the class objects or method. Suppose if we have an interface Mobile that is implemented by the iPhone class, OnePlus class, and  Sony class. Each Mobile class has a constructor that is used some set of configurations to create a mobile.

Factory design pattern
interface Mobile
{
	String IPHONE = "IPhone";
	String ONEPLUS = "OnePlus";
	String SONY = "Sony";
	void MobileBrand();
}

class Iphone implements Mobile
{
	private int ramSize;
	private String processor;
	private boolean fingerTouch;

	public Iphone(int ramSize, String processor, boolean fingerTouch) 
	{
		this.ramSize = ramSize;
		this.processor = processor;
		this.fingerTouch = fingerTouch;
	}

	@Override
	public void MobileBrand() 
	{
		System.out.println("IPhone");
	}
}

class OnePlus implements Mobile
{
	private int ramSize;
	private String processor;
	private boolean fingerTouch;
	
	public OnePlus(int ramSize, String processor, boolean fingerTouch) {
		this.ramSize = ramSize;
		this.processor = processor;
		this.fingerTouch = fingerTouch;
	}
	@Override
	public void MobileBrand() 
	{
		System.out.println("OnePlus");
	}
	
}

class Sony implements Mobile
{
	private int ramSize;
	private String processor;

	public Sony(int ramSize, String processor) 
	{
		this.ramSize = ramSize;
		this.processor = processor;
	}
	
	@Override
	public void MobileBrand() 
	{
		System.out.println("Sony");
	}
}

class MobileFactory 
{
	public static Mobile createMobile(String brandName)
	{
		if(brandName == null || brandName.equals(""))
			return null;
		if(brandName.equals(Mobile.IPHONE))
			return new Iphone(2, "A9", true);
		else if(brandName.equals(Mobile.ONEPLUS))
			return new OnePlus(3, "A1", true);
		else if(brandName.equals(Mobile.SONY))
			return new Sony(6, "A4");
		else 
			return null;
	}
}

public class ExecutionClass
{
	public static void main(String arg[])
	{
		Mobile mobile1 = MobileFactory.createMobile("IPhone");
		Mobile mobile2 = MobileFactory.createMobile("OnePlus");
		Mobile mobile3 = MobileFactory.createMobile("Sony");
	}
}

As you can see, In ExecutionClass we are creating different objects by providing a set of configurations. But if we change the configuration of each class and modify the requirement of mobile. Now we have two solutions:

1. Overload the constructor: If we overload the constructor then we have to write the extra code and in the future, if we get new requirements then we have again overloaded the constructors.

2. Change the arguments Constructor: If we change the arguments of the constructor then we have to make changes in every place wherever we are creating the object.

Both solutions have failed to resolve our problem. To resolve this problem, we can use a factory pattern. Let’s see how we can resolve it.

Factory design pattern in java with real-time example

To resolve the problem that we have discussed in the above section, we are using the factory pattern. Here we will create a Factory class that produces the object.

Factory design pattern
interface Mobile
{
	String IPHONE = "IPhone";
	String ONEPLUS = "OnePlus";
	String SONY = "Sony";
	void MobileBrand();
}

class Iphone implements Mobile
{
	private int ramSize;
	private String processor;
	private boolean fingerTouch;

	public Iphone(int ramSize, String processor, boolean fingerTouch) 
	{
		this.ramSize = ramSize;
		this.processor = processor;
		this.fingerTouch = fingerTouch;
	}

	@Override
	public void MobileBrand() 
	{
		System.out.println("IPhone");
	}
}

class OnePlus implements Mobile
{
	private int ramSize;
	private String processor;
	private boolean fingerTouch;
	
	public OnePlus(int ramSize, String processor, boolean fingerTouch) {
		this.ramSize = ramSize;
		this.processor = processor;
		this.fingerTouch = fingerTouch;
	}
	@Override
	public void MobileBrand() 
	{
		System.out.println("OnePlus");
	}
	
}

class Sony implements Mobile
{
	private int ramSize;
	private String processor;

	public Sony(int ramSize, String processor) 
	{
		this.ramSize = ramSize;
		this.processor = processor;
	}
	
	@Override
	public void MobileBrand() 
	{
		System.out.println("Sony");
	}
}

class MobileFactory 
{
	public static Mobile createMobile(String brandName)
	{
		if(brandName == null || brandName.equals(""))
			return null;
		if(brandName.equals(Mobile.IPHONE))
			return new Iphone(2, "A9", true);
		else if(brandName.equals(Mobile.ONEPLUS))
			return new OnePlus(3, "A1", true);
		else if(brandName.equals(Mobile.SONY))
			return new Sony(6, "A4");
		else 
			return null;
	}
}

public class ExecutionClass
{
	public static void main(String arg[])
	{
		Mobile mobile1 = MobileFactory.createMobile("IPhone");
		Mobile mobile2 = MobileFactory.createMobile("OnePlus");
		Mobile mobile3 = MobileFactory.createMobile("Sony");
	}
}

Here you can we are creating MobileFactory that returns the object as per requirements. Now the logic of object creation is placed in one place. If we will get new requirements in the future, then we have to make changes in only one place. The createMobile() method takes a different parameter and returns a different type of object.  

factory design pattern advantages

1. Factory design pattern allows us to write code that can change easily change according to requirement. Because the object creation is placed in one place that can handle easily. We code for interface rather than implementation.

2. Factory pattern promotes the loose-coupling, robustness, and easy to extend.  In future, if we will get a new requirement then we need to change in the Factory class, not in all the subclasses.

3. Factory pattern creates an abstraction layer between implementation and client classes and allows the sub-classes to choose the type of objects to create.

4. It works based on a Single Responsibility Principle. Because the object creation code can be moved to one place that making the code easier to support.

Factory Design Pattern Examples in JDK

In JDK, there is a various examples of the Factory pattern. The valueOf() method is used in the String and wrapper classes. it returns an object created by the factory equivalent to the value of the parameter passed.

newInstance() method which is used to create and return a new instance from the factory method every time called.

Leave a Comment