Abstract Factory Design Pattern

In Abstract Factory Design Pattern provides an interface or abstract class for creating a family of related or dependent objects, without explicitly specifying their concrete classes. It comes under creational pattern as it abstract the complex logic of creating various related object from client. It allows a client to use an interface to create a set of related objects without knowing about the concrete classes that are actually produced.

An Abstract Factory is a super factory which creates other factories. In other words, it is a factory of factory classes or It is a wrapper over factory Pattern.

Advantages of Abstract Factory Pattern

  • Abstract Factory pattern relies on object composition, as object creation is implemented in methods of factory interface.
  • It is a powerful technique that supports this major design principle "Program to an interface not an implementation".
  • It promotes loose coupling between client and concrete sub-classes.
  • It supports consistency among objects. It is the concrete factory’s job to make sure that the right objects are used together.

When we should use Abstract Factory Pattern

  • When we want to abstract the logic of object creation and want system to be independent of ways its objects are created.
  • When a system needs to create a similar or related set of objects.
  • When you want to expose an abstract library for creating families of similar objects through interfaces and by hiding implementation details.

Implementation of Abstract Factory Design Pattern

We are going to create a 'Bird' and 'Animal' interfaces and concrete classes of various birds and animals implementing these interfaces.

Bird.java
public interface Bird {
    void fly();
}
Eagle.java
public class Eagle implements Bird {

   @Override
   public void fly() {
      System.out.println("Eagle is Flying");
   }
}
Sparrow.java
public class Sparrow implements Bird {

   @Override
   public void fly() {
      System.out.println("Sparrow is Flying");
   }
}

Animal.java
public interface Animal {
    void run();
}
Lion .java
public class Lion implements Animal {

    @Override
    public void run() {
        System.out.println("Lion is Running");
    }
}
Horse.java
public class Horse implements Animal {

    @Override
    public void run() {
        System.out.println("Horse is Running");
    }
}

Next, we create an abstract factory class AbstractFactory which is extended by 'BirdFactory' and 'AnimalFactory' factory classes.

AbstractFactory.java
public abstract class AbstractFactory {
    abstract Bird getBird(String birdType);
    abstract Animal getAnimal(String animalType) ;
}
AnimalFactory.java
public class AnimalFactory extends AbstractFactory {
 
    @Override
    public Animal getAnimal(String animalType){
        if(animalType == null){
            return null;
        }  
       
        if(animalType.equalsIgnoreCase("LION")){
            return new Lion();
        } else if (animalType.equalsIgnoreCase("HORSE")){
            return new Horse();
        } else {
            return null;
        }
    }
    
    @Override
    Bird getBird(String birdType) {
        return null;
    }
}
BirdFactory.java
public class BirdFactory extends AbstractFactory {
 
    @Override
    public Bird getBird(String birdType){
     if(birdType == null){
         return null;
     }  
       
        if(birdType.equalsIgnoreCase("EAGLE")){
          return new Eagle();
     } else if (birdType.equalsIgnoreCase("SPARROW")){
          return new Sparrow();
     } else {
          return null;
     }
    }
    
    @Override
    Animal getAnimal(String animalType) {
        return null;
 }
}

Then we will create a 'FactoryCreator' class to get appropriate AbstractFactory instances as per the passed input parameter. Finally we will create 'AbstractFactoryPatternSample' which uses and instance of FactoryProducer to get concrete implementation of AbstractFactory and creates various animal and bird objects.

public class FactoryCreator {
   public static AbstractFactory getFactory(String factoryType){

    /* It is a factory of factories */
      if(factoryType.equalsIgnoreCase("BIRD")){
         return new BirdFactory();         
      } else if (factoryType.equalsIgnoreCase("ANIMAL")){
         return new AnimalFactory();
      } else {
       return null;
      }
      
   }
}
public class AbstractFactoryPatternSample {
    public static void main(String[] args) {

        //get factory of Animals using FactoryCreator 
        AbstractFactory animalFactory = FactoryCreator.getFactory("ANIMAL");

        // create animal objects using AbstractFactory interface
        Animal lion = animalFactory.getAnimal("LION");
        Animal horse = animalFactory.getAnimal("HORSE");

     //get factory of Birds using FactoryCreator 
        AbstractFactory birdFactory = FactoryCreator.getFactory("BIRD");

        // create bird objects using AbstractFactory interface
        Bird sparrow = birdFactory.getBird("SPARROW");
        Bird eagle = birdFactory.getBird("EAGLE");
       
        // Call run method of Animal interface 
        lion.run();
        horse.run();
       
        // Call fly method of Bird interface 
        sparrow.fly();
        eagle.fly();
    }
}

Output

Lion is Running
Horse is Running
Sparrow is Flying
Eagle is Flying

Important Points about Abstract Factory Pattern
  • The intent of Abstract factory design pattern is to create families of related objects without having to depend on their concrete sub-classes.
  • The client doesn't know what factory it's going to use. First, it gets a Factory and then it calls factory method to get concrete classes.
  • It is a factory of factories.

Related Topics
Factory Design Pattern
Singleton Design Pattern
Decorator Design Pattern
Facade Design Pattern
Flyweight Design Pattern
Interpreter Design Pattern
State Design Pattern
Strategy Design Pattern
Memento Design Pattern
Builder Design Pattern
Adapter Design Pattern