Abstract Factory Pattern

Abstract Factory pattern has an interface that is responsible for creating a factory of related objects without explicitly specifying their classes. Each generated factory can give the objects as per the Factory Method pattern.

Abstract Factory is also called Factory of Factories or Kit. In other words, this pattern has a super-factory which creates other factories This design pattern comes under creational pattern as it provides one of the best ways to create an object.

The intent of this pattern, according to Design Patterns by Gamma et al, is to

  • Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

This pattern provides a level of indirection that abstracts the creation of families of related or dependent objects without directly specifying their concrete classes. The "factory" object has the responsibility for providing creation services for the entire platform family. Clients the factory to create platform objects, but never create them directly.

 

Structure

The structure of factory method pattern is as shown in figure below:

abstract-factory-pattern-structure

Figure: Abstract Factory Pattern Structure

The following classes are the participants of this pattern:

  • AbstractFactory – declares a interface for operations that create abstract products.
  • ConcreteFactory – implements operations to create concrete products.
  • AbstractProduct – declares an interface for a type of product objects.
  • Product – defines a product to be created by the corresponding ConcreteFactory; it implements the AbstractProduct interface.
  • Client – uses the interfaces declared by the AbstractFactory and AbstractProduct classes.

 

Example

Let us modify an application from Factory Method Pattern which draws different geometic shapes, this time including 2D or 3D, on the basis of clien't demand. The class diagram of the applicaton is as shown below:

abstract-factory-pattern-example

Figure: Abstract Factory Method Example

Here, FactoryProvider provides factories on the basis of name provided by the client ( application.java in this case). With this factory object, we obtain the corrosponding geometric shape which we'll use to draw the shape.

 

Java Implementation

In order to implement above mentioned design, let us start with GeometricShape interface.

/**
 * Product interface
 */
public interface GeometricShape {
    void draw();
}

The concrete implementation of above interface are:

Line.java

/**
 * Concrete Product
 */
public class Line implements GeometricShape {
    @Override
    public void draw() {
        System.out.println("Line Drawn.");
    }
}

Circle.java

/**
 * Concrete product
 */
public class Circle implements GeometricShape {
    @Override
    public void draw() {
        System.out.println("Circle is drawn.");
    }
}

Sphere.java

/**
 * Concrete product
 */
public class Sphere implements GeometricShape {
    @Override
    public void draw() {
        System.out.println("Sphere drawn.");
    }
}

Now, lets create AbstractFactory.

/**
 * Abstract Factory
 */
public abstract class AbstractFactory {
    abstract GeometricShape getShape(String name);
}

The concrete classes for factories are:

TwoDShapeFactory.java

/**
 * Concrete factory
 */
public class TwoDShapeFactory extends AbstractFactory {
    @Override
    GeometricShape getShape(String name) {
        if(name.equals("line")){
            return new Line();
        }else if (name.equals("circle")){
            return new Circle();
        }
        return null;
    }
}

ThreeDShapeFactory.java

/**
 * Concrete factory
 */
public class ThreeDShapeFactory extends AbstractFactory {
    @Override
    GeometricShape getShape(String name) {
        if (name.equals("sphere")){
            return new Sphere();
        }
        return null;
    }
}

The FactoryProvider class is:

/**
 * Factory provider
 */
public class FactoryProvider {
    public static AbstractFactory getFactory(String name){
        if(name.equals("2DShapeFactory")){
            return new TwoDShapeFactory();
        }else if(name.equals("3DShapeFactory")){
            return new ThreeDShapeFactory();
        }
        return null;
    }
}

Finally, the code for client of this application is:

/**
 * Client
 */
public class Application {
    public static void main(String[] args) {
        //drawing 2D shape
        AbstractFactory factory = FactoryProvider.getFactory("2DShapeFactory");
        if (factory == null){
            System.out.println("Factory for given name doesn't exist.");
            System.exit(1);
        }
        //getting shape using factory obtained
        GeometricShape shape = factory.getShape("line");
        if(shape != null){
            shape.draw();
        }else {
            System.out.println("Shape with given name doesn't exist.");
        }

        //drawing 3D shape
        factory = FactoryProvider.getFactory("3DShapeFactory");
        if (factory == null){
            System.out.println("Factory for given name doesn't exist.");
            System.exit(1);
        }
        //getting shape using factory obtained
        shape = factory.getShape("sphere");
        if(shape != null){
            shape.draw();
        }else {
            System.out.println("Shape with given name doesn't exist.");
        }
    }
}

The output of the program is:

Line Drawn.
Sphere drawn.

The output shows that factory corrosponding to shape is required which in turn used to create an object.

Factory Method Pattern
Dynamic Proxy API