Description

The Abstract Factory design pattern is one of the Creational Design Patterns, where an interface is responsible for creating a factory of related objects without explicitly specifying their classes.

  • It is used to create objects without exposing the creation logic to the client and refer to the created object using a common interface.
  • It is used when we have a superclass with multiple subclasses, and one of the subclasses must be returned based on the input.
  • It is one of the most used design patterns in Java.

Implementation in Java

Let's follow the below approach to implement this design pattern in Java.

  • Create a class and make it an interface.
  • Create a concrete class that implements the interface.
  • Create an abstract factory that can be extended by multiple other factories.

Step 1: Create an interface.

Shape.java

public interface Shape {
    void draw();
}

Step 2: Create multiple concrete classes, all implementing the same interface.

Reactangle.java

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside Rectangle::draw() method.");
    }
}

Square.java

public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside Square::draw() method.");
    }
}

RoundedReactangle.java

public class RoundedRectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside RoundedRectangle::draw() method.");
   }
}

RoundedSquare.java

public class RoundedSquare implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside RoundedSquare::draw() method.");
   }
}

Step 3: Create an abstract class to get factories of Normal and Rounded Shape objects.

AbstractFactory.java

public abstract class AbstractFactory {
    abstract Shape getShape(String shapeType) ;
}

Step 4: Create Factory classes extending Abstract Factory to generate objects of concrete classes.

ShapeFactory.java

public class ShapeFactory extends AbstractFactory {
   @Override
   public Shape getShape(String shapeType){    
      if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();         
      }else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }	 
      return null;
   }
}

RoundedShapeFactory.java

public class RoundedShapeFactory extends AbstractFactory {
   @Override
   public Shape getShape(String shapeType){    
      if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new RoundedRectangle();         
      }else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new RoundedSquare();
      }	 
      return null;
   }
}

Step 5: Create a Factory generator/producer class to get factories by passing the input.

FactoryProducer.java

public class FactoryProducer {
   public static AbstractFactory getFactory(boolean rounded){   
      if(rounded){
         return new RoundedShapeFactory();         
      }else{
         return new ShapeFactory();
      }
   }
}

Step 6: Use FactoryProducer to get AbstractFactory to get factories of concrete classes by passing the input.

AbstractFactoryPatternDemo.java

public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
      //get shape factory
      AbstractFactory shapeFactory = FactoryProducer.getFactory(false);
      //get an object of Shape Rectangle
      Shape shape1 = shapeFactory.getShape("RECTANGLE");
      //call draw method of Shape Rectangle
      shape1.draw();
      //get an object of Shape Square 
      Shape shape2 = shapeFactory.getShape("SQUARE");
      //call draw method of Shape Square
      shape2.draw();
      //get shape factory
      AbstractFactory shapeFactory1 = FactoryProducer.getFactory(true);
      //get an object of Shape Rectangle
      Shape shape3 = shapeFactory1.getShape("RECTANGLE");
      //call draw method of Shape Rectangle
      shape3.draw();
      //get an object of Shape Square 
      Shape shape4 = shapeFactory1.getShape("SQUARE");
      //call draw method of Shape Square
      shape4.draw();
      
   }
}

Step 7: Execute the code to verify the output.

Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside RoundedRectangle::draw() method.
Inside RoundedSquare::draw() method.

Overall

We now know about the Abstract Factory design pattern and its use cases.

Related Links