Java series: Abstract factory design patterns – Part 2

 In Self-Development, Tech Corner

Design patterns are often used to simplify big chunks of code. Even to hide specific implementations from the application flow. The perfect example for this kind of problems is the factory design pattern. This is a creational design pattern that offers object creation without having to specify the exact class of the objects. It proposes using a super class and many sub-classes, which inherit from the super class.

public class Car{
  private String model;
  private int numberOfDoors;
  public Car(){
  }
  public String getModel(){
    return this.model;
  }
  public int getNumberOfDoors(){
    return this.numberOfDoors;
  }
  public void setModel(String model){ this.model = model; }
  public void setNumberOfDoors(int n){ this.numberOfDoors = n; }
}
public class Jeep extends Car{
  private boolean land;
  public Jeep(){
  }
  public void setLand(boolean land){
    this.land=land;
  }
  public boolean getLand(){
    return this.land;
  }
}
public class Truck extends Car{
  private float capacity;
  public Truck(){
  }
  public void setCapacity(float capacity){
    this.capacity=capacity;
  }
  public float getCapacity(){
    return this.capacity;
  }
}

To use this pattern, we need to implement a factory class, which will return the correct sub-class for a given input. The java classes above specify one super class (Car.java) and two sub-classes (Truck.java and Jeep.java). In our implementation we instantiate an object of the Car class and depending on the arguments, the factory class will decide whether it’s a Jeep or a Truck.

public class CarFactory{
   public Car getCarType(int numberOfDoors, String model,Float
   capacity, Boolean land){ 
      Car car=null;      
         if(capacity!=null){
            car=new Jeep();
            //implement setters
         }else{
            car=new Truck();
            //implement setters
         }
     return car;
   }
}

On runtime, the factory class instantiates the correct sub-class, considering the input.

1. ABSTRACT FACTORY DESIGN PATTERN

Abstract factory design pattern works in the same way. But, instead of a regular class, the parent class is an abstract class. Abstract classes are generally faster and easier to instantiate, because they are basically empty. The implementation is the same. The parent class is declared as abstract with all its methods. While the sub-classes need to implement the methods’ behavior of the abstract class.

We used interfaces to create the example for the Abstract factory. You can achieve the same by simply replacing the interface with an abstract class. Instead of implementing the interface, the sub-classes will extend the abstract class.

public interface Car {
   public String getModel();
   public Integer getNumberOfDoors();
   public String getType();
}
public class Jeep implements Car{
   private String model;
   private Integer numberOfDoors;
   private Boolean isLand;
   public Jeep() {}
   public Jeep(String model, Integer numberOfDoors, Boolean isLand){
     this.model = model;
     this.numberOfDoors = numberOfDoors;
     this.isLand = isLand;
   }
   public String getModel(){
     return model;
   }
   public Integer getNumberOfDoors() {
     return numberOfDoors;
   }
   public Boolean isLand() {
     return isLand;
   }
   public void setLand(Boolean isLand) { this.isLand = isLand; }
   public void setModel(String model) { this.model = model; }
   public void setNumberOfDoors(Integer numberOfDoors){    
      this.numberOfDoors = numberOfDoors; 
   }
   public String getType(){
      return "jeep";
   }
 }
public class Truck implements Car{
   private String model;
   private Integer numberOfDoors;
   private Integer numberOfWheels;
   public Truck(String model, Integer numberOfDoors, Integer numberOfWheels) {
      this.model = model;
      this.numberOfDoors = numberOfDoors;
      this.numberOfWheels = numberOfWheels;
   }
   public Truck() {}
   public String getModel() { return model; }
   public Integer getNumberOfDoors() { return numberOfDoors; }
   public Integer getNumberOfWheels() { return numberOfWheels; }
   public void setNumberOfWheels(Integer numberOfWheels) {
     this.numberOfWheels = numberOfWheels;
   }
   public void setModel(String model) { this.model = model; }
   public void setNumberOfDoors(Integer numberOfDoors) {
      this.numberOfDoors = numberOfDoors;
   }
   public String getType(){ return "truck"; }
}
public class CarFactory {
   public CarFactory(){}
   public Car getCarType(String model,Integer numberOfDoors, Integer numberOfWheels, Boolean isLand){
     if(numberOfWheels==null){
        return new Jeep(model,numberOfDoors,isLand);
     }else{
        return new Truck(model,numberOfDoors,numberOfWheels);
     }
   }
}

There is only one difference. The methods declared in the abstract class must be implemented in each of the sub-classes. The factory and the main method stay the same in both cases.

public class CarMain {
   public static void main(String[] args) {
      Car car=null;
      CarFactory carFactory=new CarFactory();
      car=carFactory.getCarType("Ford", new Integer(4), null, new Boolean(true));
     System.out.println(car.getType());
    }
}

The output is the following:

abstarct-factory

2. PROS AND CONS OF ABSTRACT FACTORY DESIGN PATTERNS

Pros:
  • allows loose coupling and a higher level of abstraction
  •  scalable and can separate certain implementations away from the application;
  •  the factory class is reusable. The code works even when you can create new classes at a lower hierarchy. Simply add the appropriate instantiation logic;
  • unit testing, because it is simple to cover all the scenarios by using the super class;
 
Cons:
  • it is often too abstract and hard to understand;
  • it is important to know when to implement the factory design pattern. In small applications it creates an overhead (more code) during object creation;
  • the factory design pattern must maintain its context. Eg. Factory design pattern is applicable when classes inherit from the same parent class or implement the same interface.

In the following blog post, we will tackle singleton design pattern. Subscribe below and never miss a story from our Java series: “Good practices and recommendations”.

Recommended Posts
agile transformationjava developer

SINGULAR STORY IN YOUR INBOX

Get news about career opportunities and product updates once a month.