Factory Method Design Pattern

Factory Method Design Pattern | The factory method design pattern provides the set of rules and guidelines for multiple factories when they are creating objects for the same family classes.

The classes that belong to the same inheritance hierarchy either having a common superclass or common implementation interface can be called as same family classes.

Note:- The Java factory method is different from the factory method design pattern. In Java, any method which creates and returns objects is called the factory method. The Java factory method is used in almost all creational design patterns like Singleton Pattern, Factory Pattern, Factory Method Pattern, Strategy Pattern e.t.c.

Need of Factory Method Design Pattern

Let us see a story so that you can easily understand the need for factory method design patterns and how it is solving the problem.

Assume there is a company in the Car manufacturing industry. They have two models Model1Car and Model2Car. The company has established two manufacturing plants (factory) at two different locations. The NorthFactory is used to manufacture cars for the customers from the north side of the country, similarly, the SouthFactory is used to manufacture for the customers from the south side of the country. Both factories are manufacturing both models of the car.

Car (AC)
  |=> Model1Car (CC)
  |=> Model2Car (CC)
Company (AC)
  |=> NorthFactory (CC)
  |=> SouthFactory (CC)

Here, AC means Abstract class, and CC means Concrete class.

The company had not given any standards (rules and guidelines) to create the Cars. Therefore both factories had created their own standards and started manufacturing the car models. The NorthFactory was giving much importance to the quality and they were following many standards to create the cars, but the SouthFactory was giving more importance to the production cost, and to reduce it they were following fewer standards compared to the NorthFactory.

Both factories belong to the same company but because of their quality standards north side customers were getting good quality and south side customers were getting lesser quality. After some time south customers started demanding cars manufactured only from the NorthFactory, else they won’t buy the car from that company. Due to these issues, In the north side of the country, the company was growing but on the south side of the country, the company went into the loss. The company got a bad reputation in the market, and it was not good for the growth of the company. 

To make a successful business the key is:- “Wherever you buy the product you should get the same quality.” To solve this problem company provided a set of rules and guidelines (standards) for both factories. Now, both factories must follow that standard to manufacture the car. In the future, if the company will start any new factory then that factory also must follow those standards. Finally, every customer gets the same product, and it increased the brand image of the company. 

Factory Method Pattern vs Template Pattern

If you know the template design pattern then you may feel the factory method pattern and template pattern same, but that’s not true. Both are different from each other.

In the factory method pattern, we take one superclass which provides rules and guidelines. The sub-classes which are implementing that superclass must follow those rules. The sub-classes can’t add/remove/skip/modify any standard.

In the template pattern, the sub-classes which are implementing the superclass can modify/add/remove/skip the template. We can understand it through our resume template. Assume we downloaded one resume template from the internet, then we won’t continue with the same. We will take that template, remove the unnecessary details, add the required information, and we can do whatever things we want because there is no restriction available.

We have already seen one example (car) for the factory method design pattern. Let us see another example:- In an interview for the Job, the company defines certain processes (standards) for the candidates i.e. first written test => then round-1 => then round-2 => then HR round. These steps should be followed by everyone and they will not be modified for any job seekers. Here, the factory method is not defining how a written test should be conducted i.e. it won’t define the method for any particular process. It will define the execution order, and create the object.

Before discussing more on factory method pattern and going to the problem-code, first solve the below quiz (This concept will be used while solving our problem.)

class Test {
   public void m1() {
     m2();
   }
   public void m2() {
      System.out.println("Test-m2");
   }
}

class Demo extends Test {
   public void m2() {
      System.out.println("Demo-m2");
   }
}

In user class,

Demo d = new Demo();
d.m1();

Q) What will be the output?

a) Test-m2
b) Demo-m2
c) Compile time error
d) Exception

View Answer Answer:- (b) Demo-m2

In the user class, the m1() method is called on the Demo class object. The m1() method is internally calling the m2() method and since it is called on the Demo class object therefore first it will check m2() method is available in the Demo class or not. Yes, it is available therefore m2() method will be executed from the Demo class. If the Demo class won’t contain the m2() method then it will search for it in the superclass.

Factory Method Design Pattern Example

In this example, we will use Factory Pattern (Simple Factory Pattern) multiple times. Pre-requisite:- Factory Pattern Design Pattern.

First, see the problem code at GitHub:- FactoryMethodDP–Problem

The problem project structure is,

FactoryMethodDP-Problem
  |=> src
      |=> com.kp.comp
          > CompanyCar.java (AC)
          > Model1Car.java
          > Model2Car.java
          > Model3Car.java
      |=> com.kp.factory
          > NorthFactory.java
          > SouthFactory.java
      |=> com.kp.test
          > NorthCustomer.java
          > SouthCustomer.java

In the problem code, North and South factories are following their own standards to create the car. But the standards should be given by the company and both factories must follow them.

Solution using Factory Method Design Pattern

To overcome the above application problem, develop a superclass for all factory classes defining the standards.

FactoryMethodDP-Solution
|=> src
      |=> com.kp.comp
          > CompanyCar.java (AC)
          > Model1Car.java
          > Model2Car.java
          > Model3Car.java
      |=> com.kp.factory
          > CompanyFactory.java 
          > NorthFactory.java
          > SouthFactory.java
          > CompanyCarFactoryLocator.java
      |=> com.kp.test
          > NorthCustomer.java
          > SouthCustomer.java

The component class

// CompanyCar.java (AC=> Abstract Class)
package com.kp.comp;
public abstract class CompanyCar {
   private long engineId;
   private String engineCC;
   public abstract void drive();
}
// Model1Car.java
package com.kp.comp;
public class Model1Car extends CompanyCar {
   private String accelerationLevel;
   @Override
   public void drive() {
      System.out.println("Driving Model-1 Car from Company-X.");
   }
}

Model1Car, Model2Car, Model3Car are extended from the CompanyCar class. Based on the Model1Car.java, you can develop the Model2Car.java and Model3Car.java classes.

Now the most important part of our application i.e. implements the Factory method design pattern by giving some standards (rules and guidelines). Add one new abstract class in the com.kp.factory package.

// CompanyFactory.java
package com.kp.factory;

// class having Factory Method design pattern
// (Given by Company)
import com.kp.comp.CompanyCar;

public abstract class CompanyFactory {

   /*Processes used in Car manufacturing*/
   // North & South factory must implement them
   public abstract void paint();
   public abstract void assemble();
   public abstract void roadTest();
   public abstract void oiling();
   public abstract CompanyCar createCar(String model);
   
   // method having factory method design pattern logic
   public CompanyCar orderCar(String type) {
      // rules and guidelines (standard)
      paint(); // 1st paint
      assemble(); // 2nd assemble
      oiling(); // 3rd oiling
      CompanyCar car = createCar(type); // 4th create Car
      roadTest(); // 5th road test
      return car;
   }
}

The advantage with the above approach is:- every factory (north and south) will take care of manufacturing the Company-X car, but the complete control of standards and processes to manufacture the car will be done across the multiple factories in the same manner as it is controlled by the superclass that contains factory method logic.

Now, develop the NorthFactory and SouthFactory by extending from the CompanyFactory abstract class. The NorthFactory and SouthFactory classes are also using the Simple Factory Pattern to provide abstraction on the car-model class object creation process.

// NorthFactory.java
package com.kp.factory;
import com.kp.comp.CompanyCar;
import com.kp.comp.Model1Car;
import com.kp.comp.Model2Car;
import com.kp.comp.Model3Car;

public class NorthFactory extends CompanyFactory {

   /*Some processes used in Car manufacturing*/
   public void paint() {
      System.out.println("NorthFactory: Painting Company-X car");
   }
   public void assemble() {
      System.out.println("NorthFactory: Assembling Company-X car");
   }
   public void roadTest() {
      System.out.println("NorthFactory: "
                       + "Road Testing of Company-X car");
   }
   public void oiling() {
      System.out.println("NorthFactory: Oiling of Company-X car");
   }
   
   /* Implementing Simple Factory Pattern to provide
    * abstraction on the Car creation process. 
    **/
   // Java factory method  
   public CompanyCar createCar(String model) {
      CompanyCar car = null;
      // create one of the several model car based on requirement
      if(model.equalsIgnoreCase("model1")) {
         car = new Model1Car();
      } else if(model.equalsIgnoreCase("model2")) {
         car = new Model2Car();
      } else if(model.equalsIgnoreCase("model3")) {
         car = new Model3Car();
      } else {
         throw new 
           IllegalArgumentException("Invalid Car-Model Type");
      }
      
      // return car
      return car;
   }
}

The NorthFactory and SouthFactory are not defining the order of method execution, it is already defined in the superclass and that is the rules (both factories can’t modify/skip/add any order).

// SouthFactory.java
package com.kp.factory;
import com.kp.comp.CompanyCar;
import com.kp.comp.Model1Car;
import com.kp.comp.Model2Car;
import com.kp.comp.Model3Car;

public class SouthFactory extends CompanyFactory {

   /* Some processes used in Car manufacturing */
   public void paint() {
      System.out.println("SouthFactory: Painting Company-X car");
   }
   public void assemble() {
      System.out.println("SouthFactory: Assembling Company-X car");
   }
   public void roadTest() {
      System.out.println("SouthFactory: " 
                       + "Road Testing of Company-X car");
   }
   public void oiling() {
      System.out.println("SouthFactory: Oiling of Company-X car");
   }
   
   /* Implementing Simple Factory Pattern to provide
    * abstraction on the Car creation process. 
    **/
   // Java factory method  
   public CompanyCar createCar(String model) {
      CompanyCar car = null;
      // create one of the several model car based on requirement
      if(model.equalsIgnoreCase("model1")) {
         car = new Model1Car();
      } else if(model.equalsIgnoreCase("model2")) {
         car = new Model2Car();
      } else if(model.equalsIgnoreCase("model3")) {
         car = new Model3Car();
      } else {
         throw new 
           IllegalArgumentException("Invalid Car-Model Type");
      }
      
      // return car
      return car;
   }
}

Currently, there are two factories, and to provide abstraction on the North or South Factory object creation create one separate class by implementing Simple Factory Design Pattern.

//  CompanyCarFactoryLocator.java
package com.kp.factory;

// This class is optional
// It is only to provide abstraction on 
// North or south factory object creation process
public class CompanyCarFactoryLocator {

   // factory pattern
   // To return of the the CompanyFactory type 
   public static CompanyFactory buildCarFactory(String location) {
      if(location.equalsIgnoreCase("north")) {
         return new NorthFactory();
      } else if (location.equalsIgnoreCase("south")) {
         return new SouthFactory();
      } else {
         throw new 
           IllegalArgumentException("Invalid Factory location");
      }
   }
}

Now, let us develop the client/user class.

// NorthCustomer.java
package com.kp.test;
import com.kp.comp.CompanyCar;
import com.kp.factory.CompanyCarFactoryLocator;
import com.kp.factory.CompanyFactory;
public class NorthCustomer {
   public static void main(String[] args) {
      CompanyFactory factory = 
         CompanyCarFactoryLocator.buildCarFactory("north");
      CompanyCar car = factory.orderCar("model1");
      car.drive();
   }
}

Output:-

NorthFactory: Painting Company-X car
NorthFactory: Assembling Company-X car
NorthFactory: Oiling of Company-X car
NorthFactory: Road Testing of Company-X car
Driving Model-1 Car from Company-X.

Here buildCarFactory() method is passing the location of the factory, and therefore it creates and return the NorthFactory object. On this object, we are calling the orderCar() method by passing the model name. The orderCar() method is defined in the superclass (CompanyFactory.java) and it is calling different methods which are implemented on sub-classes. Since the orderCar() method is called on sub-class object (NorthFactory) therefore paint(), assemble(), oiling(), createCar(type), and roadTest() methods will be called from the NorthFactory class.

// SouthCustomer.java
package com.kp.test;
import com.kp.comp.CompanyCar;
import com.kp.factory.CompanyCarFactoryLocator;
import com.kp.factory.CompanyFactory;
public class SouthCustomer {
   public static void main(String[] args) {
      CompanyFactory factory = 
          CompanyCarFactoryLocator.buildCarFactory("south");
      CompanyCar car = factory.orderCar("model1");
      car.drive();
   }
}

Output:-

SouthFactory: Painting Company-X car
SouthFactory: Assembling Company-X car
SouthFactory: Oiling of Company-X car
SouthFactory: Road Testing of Company-X car
Driving Model-1 Car from Company-X.

See the solution code in the GitHub:- FactoryMethodDP-Solution

Leave a Comment

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