Introduction

Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. In Factory pattern, we create object without exposing the creation logic to client and the client use the same common interface to create new type of object. It relies on inheritance: object creation is delegated to subclasses which implement the factory method to create objects. Factory Method is similar to Abstract Factory but without the emphasis on families.

The Factory Method pattern suggests replacing direct object creation (using a new operator) with a call to a special “factory” method.

Advantage

  • Factory Method Pattern allows the sub-classes to choose the type of objects to create.
  • It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code. That means the code interacts solely with the resultant interface or abstract class, so that it will work with any classes that implement that interface or that extends that abstract class.

 

Implementation

  • The client needs a product, but instead of creating it directly using the new operator, it asks the factory object for a new product, providing the information about the type of object it needs.
  • The factory instantiates a new concrete product and then returns to the client the newly created product.
  • The client uses the products as abstract products without being aware about their concrete implementation.

Example

// Super class in factory design pattern can be an interface, abstract class or a normal java class.
public abstract class Computer {
  
  public abstract String getRAM();
  public abstract String getHDD();
}

// Two sub-classes PC and Server with below implementation.
public class PC extends Computer {

  private String ram;
  private String hdd;
  
  public PC(String ram, String hdd){
    this.ram=ram;
    this.hdd=hdd;
  }

  @Override
  public String getRAM() {
    return this.ram;
  }

  @Override
  public String getHDD() {
    return this.hdd;
  }
}

public class Server extends Computer {

  private String ram;
  private String hdd;
  
  public Server(String ram, String hdd){
    this.ram=ram;
    this.hdd=hdd;
  }

  @Override
  public String getRAM() {
    return this.ram;
  }

  @Override
  public String getHDD() {
    return this.hdd;
  }
}

// Factory class
public class ComputerFactory {

  public static Computer getComputer(String type, String ram, String hdd){
    if("PC".equalsIgnoreCase(type)) {
      return new PC(ram, hdd);
    }
    else if("SERVER".equalsIgnoreCase(type)) {
      return new Server(ram, hdd);
    }

    return null;
  }
}

// Program that uses above factory design pattern implementation.
public class TestFactory {

  public static void main(String[] args) {
    Computer pc 	= ComputerFactory.getComputer("PC","2 GB","500 GB");
    Computer server = ComputerFactory.getComputer("SERVER","16 GB","1 TB");
  }
}