Factory Pattern in Java

In this tutorial, we will discuss the following points:- What is the factory pattern? What are the problems and why do we need to use the Factory pattern? How factory pattern in Java solves those problems. What are real-time examples of factory design patterns in Java? 

There are four different terms that contain “Factory” words:-

  1. Static Factory Method:- Any method which creates and returns an object is called a factory method. Generally, they are static methods therefore they are called static factory methods.
  2. Factory Pattern (or Simple Factory Pattern)
  3. Factory Method Design Pattern
  4. Abstract Factory Design Pattern

In this tutorial, we will discuss the Simple Factory Pattern. Among the above four terms except “Static Factory Method”, the other three are design patterns. The Factory Pattern is one of the most used creational design patterns in Java. While learning Factory pattern, always consider the client application and business logic will be developed by two different programmers. In this way, you can understand it very easily.

Sometimes an application or framework at runtime, can’t anticipate the class of object that it must create. The application/framework may know that it has to instantiate classes, but it may only know about abstract classes or interfaces, which it can’t instantiate. Thus the application class may want its subclasses to specify the objects to be created.

The main advantage of using factory pattern is:- it abstracts the object creational process of the classes.

The factory pattern handles the problems of object creation by defining a separate method for creating the objects, this method optionally accepts parameters defining for which class the object should be created, and returns the created object.

Problems – Need of Factory Pattern

Problem1:- Different objects for different classes will be created using different techniques but we don’t want to expose those techniques to the end-user.

Making client applications or user application developers know the process of creating objects for the class is going to become a bit heavy for them.

For example:- To have our own bike, we do not manufacture Bike ourselves because it will take a lot of time, effort, and also be very complex. Instead to get a bike we go to a Bike factory that is proficient in bike manufacturing. After getting the order based on the model number they will manufacture the bike or deliver the already manufactured bike of that model. We don’t suffer to know the formula of creating engines, tyres, assembling processes, and testing. We just need to order the bike therefore we can say the bike manufacturing company is providing the abstraction on the bike creation process.

Similarly, we have many classes and we need only one object of those classes based on the data we supplied. But we don’t want to know the process of the object creation (like how to create that object, what dependencies are required, those dependencies need what other dependencies e.t.c.). We just want to approach a factory and get the object based on our data supplied. The factory should take care of the object creation, dependencies, and all the other things. This factory is nothing but Factory Patterns.

Problem2:- Sometimes we can’t anticipate which class object has to be created until runtime so creating objects for all the classes and using only one object from those objects is bad practice. It is a waste of memory and CPU time.

Problem3:- If the object creation process is very complex then better not to expose that process directly to the user application or client application developer. It is better to provide abstraction on the object creation process.

Solution using Factory Pattern

We can solve the above problems using Factory Pattern. It creates objects for one of the several related/possible classes based on data that we supply by providing abstraction on the object creation process. That means objects for the remaining subclasses/other classes will not be created. If necessary then it will create and assign its dependent objects.

Usually, all classes that return have a common parent class and common methods, but each performs a task differently and is optimized for different kinds of data.

Intent:

  • Creates objects without exposing the instantiation logic to the client (provides an abstraction on object creation process).
  • Refers to the newly created object through a common interface.

Examples

Let us see some real-time examples of Factory patterns used in JDBC, Hibernate, and Spring. 

Factory Pattern in JDBC

In JDBC we use DriverManager.getConnection(-,-,-) to get the connection object. It creates and returns a JDBC Connection object for particular database software based on the passed URL. 

Conncection con = 
       DriverManager.getConnection(URL, username, password);

If we pass the URL of the Oracle database, then it will create and return a Connection for the Oracle database. Similarly, if we pass the URL of the MySQL database, then it will create and return Connection for the MySQL database, and so on.

As a programmer, we don’t bother about how these connection objects are created. We never worry about the class name (belonging to that database software) from which connection object is created, we don’t know internally whether it is using which method or “new” operator to create the object. We just need to call the method and get the object. Programmers don’t need to know anything related to the Connection object creation process.

Another example:- In JDBC programming, all JDBC objects are created through a factory pattern process. 

Statement st = con.createStatement();
ResultSet rs = st.executeQuery();
PreparedStatement ps = con.PreparedStatement();

Not only Connection objects but, In the creation of all these JDBC objects the Factory Pattern is involved either directly or indirectly.

Factory Pattern in Hibernate

The SessionFactory of the Hibernate framework is given based on Factory Design Pattern because it provides an abstraction on Hibernate Session object creation process. 

Session ses = factory.openSession();

We are just calling the openSession(-) method and getting the Session object, and we didn’t bother about how the Session object is created internally. Actually, the Session object internally contains a JDBC connection object. JDBC connection creation process needs URL, username, and password, but we don’t need to know how it is collecting this information from configuration files e.t.c. The Session object also contains lots of other objects but we don’t worry about them. Everything is abstracted (hidden) here. Abstraction means hiding the process/implementing while utilizing the functionality. 

Factory Pattern in Spring

The factory.getBean(-) or ctx.getBean(-) method of Spring creates and returns Spring bean object by hiding its object creational process based on the bean id we pass. As an application developers, we don’t bother about how it creates objects, we just need to call the getBean(-) method, receive the object, and perform the next activities.

Spring IOC container name is BeanFactory i.e. it is a factory to create and return Spring bean objects by providing abstraction on their object creation process. The spring IOC container is designed based on two design patterns, and they are:- Simple Factory Pattern and FlyWeight Pattern.

More examples of the factory pattern in the Java language are given at the end.

How to implement Factory Pattern

In order to work with factory patterns, we need to have several classes. And based on the data that is passed, one class object should be created and returned. 

Then the question came into our mind “How to keep several classes as related classes?”:- By making those classes either extend from common class or by implementing it from a common interface. For our purpose, using the interface option is far better than class.

Due to this, we can refer to that object returned by the factory using this common interface reference variable/common superclass reference variable.

In Java, we always don’t use the “new” keyword to create objects. There are different ways to create objects like- the “new” keyword, by calling a static factory method on the class (singleton), passing another object as a reference, cloning process, and e.t.c. A Java method internally uses one of these ways to create objects therefore it is better to have abstraction on that object creation process.

Without using the interface,

class A {}
class B {}
class C {}

In user class, to create the object for A, B, and C class:-

A a = new A();
B b = new B();
C c = new C();

With using the interface,

interface X {}
class A implements X {}
class B implements X {}
class C implements X {}

In user class, to create the object for A, B, and C class:-

// good approach
X x1 = new A();
X x2 = new B();
X x3 = new C();

Every class that is representing a factory pattern will have one factory method accepting and returning one of the several related class object based on the accepted data. This factory method will have a common superclass/interface as the return type.

Note:- In Java, any method which creates and returns objects is called the factory method. (This Java’s factory method is different from the Factory Method Design Pattern, both are not the same).

// implementation of factory pattern
public class MyFactory {
  // static factory method having interface return type 
  public static X createObject(String type) {
    if(type.equalsIgnoreCase("a"))
      return new A();
    else if(type.equalsIgnoreCase("b"))
      return new B();
    else
      return new C();
  }
}

In user class (Client/user application),

// to create object of A class
X x1 = MyFactory.createObject("A");

// to create object of B class
X x2 = MyFactory.createObject("B");

// to create object of C class
X x3 = MyFactory.createObject("C");
  • If the Java method return type is an interface then the method returns one implementation class object of that interface.
  • If the Java method return type is an abstract class then the method returns one sub-class object of that abstract class.
  • If the Java method return type is a concrete class then the method can return a concrete class object or one of its subclass objects.

Why return type of factory method should be common type

Why should the return type of factory method be a common interface or common class? Let us understand it through the JDBC connection example. The Connection is an interface given in JDBC API. While developing JDBC drivers for the Oracle database they implement this interface and write logic to establish the connection between the Java application and the Oracle database. Similarly, while developing JDBC drivers for MySQL databases they also implement this interface and write logic to establish the connection with MySQL databases. 

Currently, we have many databases, and for one database a lot of JDBC drivers are given by different vendor companies. Assume if they return their own Class type then our application code will be specific to one JDBC driver software, and it will provide tight coupling. To use different JDBC drivers we have to modify our application code, and with this limitation, we can’t think about ORM frameworks (like Hibernate) where we are also able to change databases without modifying the Java code.

The return type should not change based on the JDBC driver or database software. For every JDBC driver, the name of the implementation class may change but the return type of the method should be a common interface, then it will provide loose coupling. Therefore, we can work with any JDBC driver without changing our application code

Steps to Implement Factory Pattern

Assume we will have multiple classes, and in the user class, we need to create an object of one among these classes based on our requirement. Then we should use the factory pattern as given below.

Step1:- Create an interface.

interface X{}

Step2:- Develop classes by implementing that interface.

class A implements X {}
class B implements X {}
class C implements X {}

Step3:- Create a Factory class.

// implemention of factory pattern
public class MyFactory {
  // factory method logic
}

Step4:- In Factory class, develop a factory method. The factory method should be:-

  • Static method. So that user class developers can access it without creating objects for the Factory class.
  • Return one of the several related class objects based on the accepted data through the interface.
// implementation of factory pattern
public class MyFactory {
  // factory method having interface return type 
  public static X createObject(String type) {
    // sample code (logic based on application)
    if(type.equalsIgnoreCase("a"))
      return new A();
    else if(type.equalsIgnoreCase("b"))
      return new B();
    else
      return new C();
  }
}

Now, to create objects of the required class the client application developer will use this factory class and factory method by passing the class name.

// to create object of A class
X x1 = MyFactory.createObject("A");

// to create object of B class
X x2 = MyFactory.createObject("B");

// to create object of C class
X x3 = MyFactory.createObject("C");

Application Example

Let us develop a simple application to see an implementation of Factory design patterns. First, we will see how it can be done without using a factory pattern and then we will see how factory pattern is simplifying our work by providing abstraction and loose coupling.

Application Description

There are three models of Bike:- Model-1, Model-2, and Model-3. Create a bike based on the customer requirement. The process to create bike:-

  • Create Tyres
  • Create Bike
  • Assemble the bike
  • Road test

Try it yourself without using factory patterns. See the code at GitHub:- FactoryDP – Problem.

In the problem code, client application developers have to know the process of bike creation and follow the steps. For every customer, this process should be followed in the client application. To solve this problem we will use the Factory design pattern. 

The package structures for the application,

=>src
   => com.kp.comps
      => Bike.java
      => BikeTyres.java
      => Model1Bike.java
      => Model2Bike.java
      => Model3Bike.java
   => com.kp.factory
      => BikeFactory.java
   => com.kp.test
      => Customer1.java
      => Customer2.java

The interfaces and classes in the comps package.

// Bike.java (Interface)
package com.kp.comps;
public interface Bike {
   public void assemble();
   public void roadTest();
}
// BikeTyres.java
// Bike class internally needs Tyre component
package com.kp.comps;
public class BikeTyres {
   public BikeTyres() {
      System.out.println("BikeTyres.BikeTyres()");
   }
   @Override
   public String toString() {
      return "BikeTyres";
   }
}
// Model1Bike.java
package com.kp.comps;
public class Model1Bike implements Bike {
   private BikeTyres tyres;
   
   public Model1Bike(BikeTyres tyres) {
      System.out.println("Model1Bike.Model1Bike()");
      this.tyres = tyres;
   }

   @Override
   public void assemble() {
      System.out.println("Model-1 bike is assembled");
   }

   @Override
   public void roadTest() {
      System.out.println("Model-1 bike is roadTest");
   }

   @Override
   public String toString() {
      return "Model-1 Bike with [tyres=" + tyres + "]";
   }   
}

Model2Bike.java and Model3Bike.java are very similar to Model1Bike.java, only the class name will change.

Implementation of Factory Design Pattern,

// BikeFactory.java
// This class is implementing Factory Pattern
package com.kp.factory;

import com.kp.comps.Bike;
import com.kp.comps.BikeTyres;
import com.kp.comps.Model1Bike;
import com.kp.comps.Model2Bike;
import com.kp.comps.Model3Bike;

public class BikeFactory {

   // static factory method
   public static Bike getBike(String type) {

      // variables
      Bike bike = null;

      // create BikeTyres object
      BikeTyres tyres = new BikeTyres();
      if(type.equalsIgnoreCase("model1")) {
         bike = new Model1Bike(tyres);
      } else if(type.equalsIgnoreCase("model2")) {
         bike = new Model2Bike(tyres);
      } else if(type.equalsIgnoreCase("model3")) {
         bike = new Model3Bike(tyres);
      } else {
         throw new IllegalArgumentException("Invalid Bike Model");
      }

      // assemble the bike
      bike.assemble();
      // road test
      bike.roadTest();
      
      // return
      return bike;
   }
}

Note:- Instead of if-else you can also use switch-case statements.

Now, as a client application developer no need to know the bike creation process, Just call the factory method using the factory class name by passing the required model name and getting the object. 

// Customer1.java
package com.kp.test;
import com.kp.comps.Bike;
import com.kp.factory.BikeFactory;

/* Requirement:- customer-1 want Model-1 bike*/
public class Customer1 {

   public static void main(String[] args) {
      Bike bike = BikeFactory.getBike("model1");
      System.out.println(bike);
   }
}
// Customer2.java
package com.kp.test;
import com.kp.comps.Bike;
import com.kp.factory.BikeFactory;

/* Requirement:- customer-2 want Model-3 bike*/
public class Customer2 {
   public static void main(String[] args) {
      Bike bike = BikeFactory.getBike("model3");
      System.out.println(bike);
   }
}

See the complete code at GitHub:- FactoryDP-Solution.

Compare the client code with and without Factory design pattern, there you can see the loose coupling and advantage of the factory pattern. Without using the factory design pattern, client application developers have to deal with all dependencies like tyre, engine, necessary equipment, assembling process, and e.t.c but with using factory pattern no need to deal with all those processes. 

While learning Factory pattern assumes client application and business logic will be developed by two different programmers, then you can understand it easily. This whole thing has been done only to simplify the client application developer Job.

Improving Factory Pattern in Java Code by Involving Enum Constants

We can improvise the above code a little bit. In the factory class, we were hard coding values by writing “model1”, and “model2”. Instead of passing these values as strings, we can give Enum constants to the end-user to use them. 

Add BikeType enum in the factory package,

// BikeType.java
package com.kp.factory;
public enum BikeType {
   MODEL1, 
   MODEL2,
   MODEL3
}

Here declaring MODEL1 is similar to writing public static final MODEL1 = new BikeType(); Now, the factory class can be developed as,

// BikeFactory.java
package com.kp.factory;
import com.kp.comps.Bike;
import com.kp.comps.BikeTyres;
import com.kp.comps.Model1Bike;
import com.kp.comps.Model2Bike;
import com.kp.comps.Model3Bike;

public class BikeFactory {

   // static factory method
   public static Bike getBike(BikeType type) {

      // variables
      Bike bike = null;

      // create BikeTyres object
      BikeTyres tyres = new BikeTyres();
      if(type==BikeType.MODEL1) {
         bike = new Model1Bike(tyres);
      } else if(type==BikeType.MODEL2) {
         bike = new Model2Bike(tyres);
      } else if(type==BikeType.MODEL3) {
         bike = new Model3Bike(tyres);
      } else {
         throw new IllegalArgumentException("Invalid Bike Model");
      }

      // assemble the bike
      bike.assemble();
      // road test
      bike.roadTest();
      
      // return
      return bike;
   }
}

And the customer can use it as,

// Customer1.java
package com.kp.test;
import com.kp.comps.Bike;
import com.kp.factory.BikeFactory;
import com.kp.factory.BikeType;
/* Requirement:- customer-1 want Model-1 bike*/
public class Customer1 {
   public static void main(String[] args) {
      Bike bike = BikeFactory.getBike(BikeType.MODEL1);
      System.out.println(bike);
   }
}
// Customer2.java
package com.kp.test;
import com.kp.comps.Bike;
import com.kp.factory.BikeFactory;
import com.kp.factory.BikeType;
/* Requirement:- customer-2 want Model-3 bike*/
public class Customer2 {
   public static void main(String[] args) {
      Bike bike = BikeFactory.getBike(BikeType.MODEL3);
      System.out.println(bike);
   }
}

See complete code at GitHub:- FactoryDP-Solution2-Enum

Real Time use case of Factory Pattern

We have already discussed how Factory Pattern is used in JDBC, Hibernate, and Spring. Some more real-time examples where Factory Pattern is used:-

  • java.util.Calendar#getInstance():- The getInstance() method calling Locale.getDefault(-) method, and getDefault(-) is using switch case to return Locale type. You can observe it in JDK source code.
  • java.util.ResourceBundle#getBundle():- The getBundle() method internally calls Locale.getDefault(-) method.
  • java.text.NumberFormat#getInstance()
  • java.nio.charset.Charset#forName()
  • java.net.URLStreamHandlerFactory#createURLStreamHandler(String) (Returns singleton object per protocol)
  • java.util.EnumSet#of()
  • javax.xml.bind.JAXBContext#createMarshaller() and other similar methods
  • java.sql.DriverManager#getConnection(String url, String user, String pws)

Some situations where we can use factory pattern:- The application wants to communicate with different databases like Oracle, MySQL, and PostgreSQL based on the client application requirement then use Factory Pattern.

We will develop more examples on Factory Pattern while discussing Abstract Factory Pattern, Builder Pattern. In those pattern examples, factory patterns will be used.

FAQ

Q1) What is the use of factory patterns?
Factory pattern is used to provide abstraction on the object creation process.

Q2) What is the factory pattern explained with an example?
The factory pattern handles the problems of object creation by defining a separate method for creating the objects, this method optionally accepts parameters defining for which class the object should be created, and returns the created object.

Q3) What are the types of factory patterns?
We have three different design patterns which contain “Factory” words, and they are:- Factory Pattern (or Simple Factory Pattern), Factory Method Design Pattern, Abstract Factory Design Pattern.

Q4) What problem does factory pattern solve?
Factory Pattern solves the problems of object creation. It creates one of the several related/possible classes based on data that we supply by providing abstraction on the object creation process.

Q5) How do you implement a factory pattern?
To implement factory pattern,
a) Create an interface.
b) Develop classes by implementing that interface.
c) Create a Factory class.
d) In the Factory class, develop a factory method. The factory method should be a static method and return one of the several related classes object based on the accepted data through the interface.

Q6) What is the main benefit of using factory patterns?
The main advantage of using factory pattern is:- it abstracts the object creational process of the classes.

Q7) What is the difference between factory and builder patterns?
A factory pattern is used for creating an instance of an object where the dependencies of the object are entirely held by the factory. Builder pattern builds a complex object using simple objects and using a step-by-step approach.

Q8) Is dependency injection a factory pattern?
No, dependency injection is not a factory pattern. Both are different.

If you enjoyed this post, share it with your friends. Do you want to share more information about the topic discussed above or do you find anything incorrect? Let us know in the comments. Thank you!

Leave a Comment

Your email address will not be published. Required fields are marked *