Abstract Factory Design Pattern Java Real World Example

Abstract Factory Design Pattern

Abstract Factory Design Pattern is one of the Creational pattern and almost similar to Factory Method Pattern except because it’s more like a factory of factories. In the Factory Method Pattern, we have a single factory class that returns the different sub-classes based on the input provided.

Abstract Factory Design Pattern is used when we have two or more objects which works together forming a kit/set and there can be multiple sets or kits that can be created by client code. We separate client code from these concrete objects forming such a set and also from the code that creates such a set.

Abstract Factory Design Pattern implementation provides us a framework that allows us to create objects that follow a general pattern. So at runtime, the abstract factory is coupled with any desired concrete factory that can create objects of the desired type.

Abstract Factory Design Pattern is a super-factory that creates other factories. It offers the interface for creating a family of related objects without explicitly specifying their classes.

This tutorial is a part of the Creational Design Pattern Series. Take a look at other Creational Design Patterns:

  1. Singleton Creational Design Pattern Java Explained [6 Code Example]
  2. Factory Design Pattern Java Simplified [Simple Real World Example]
  3. Factory Method Design Pattern Java Simple Detailed Examples
  4. Abstract Factory Design Pattern Java Real World Example
  5. Builder Design Pattern Java Real World Example
  6. Prototype Design Pattern Java Real World Example

 

Implementation of Abstract Factory Design Pattern

  1. Create an Abstract Factory as an Interface or an Abstract Class.
  2. Abstract factory defines abstract methods for creating products.
  3. Provide a concrete implementation of factory for each set of products.
  4. Abstract Factory makes use of factory method pattern. Abstract Factory is an object with multiple factory methods.

 

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

How is Java Pass by Value and Not by Reference [4 Examples]

Real World Example Implementation of Abstract Factory Design Pattern

Let’s consider a scenario where a Laptop dealer (Client) buy a Laptop (Product) as per customer need.
The client can order two Brand Laptop, Apple and Dell with variable storage size.

Abstract Factory Design Pattern

 

Super Class

Storage and Processor are the interface acting as an Abstract Product. This interface contains a declaration of a common functionality.

package com.adevguide.java.designpatterns.abstractfactory;

public interface Storage {

    void getType();
}
package com.adevguide.java.designpatterns.abstractfactory;

public interface Processor {

    void attachStorage(Storage storage);

    void printSpecs();

}

 

Sub Class

AppleProcessor, AppleStorage, DellProcessor, and DellStorage are sub class implementing interface Processor and Storage.

package com.adevguide.java.designpatterns.abstractfactory;

public class AppleProcessor implements Processor {

    private String storage;
    
    public AppleProcessor() {
        System.out.println("Intel Processor will be used for Apple Laptop");
    }

    public void attachStorage(Storage storage) {
        this.storage=storage.toString();
        System.out.println(storage + " is attached to Apple Laptop");
    }

    public void printSpecs() {
        System.out.println(this.toString());

    }

    @Override
    public String toString() {
        return "AppleProcessor is created using Intel Processor and "+this.storage;
    }

}
package com.adevguide.java.designpatterns.abstractfactory;

public class AppleStorage implements Storage {

    private int storageSize;

    public AppleStorage(int storageSize) {
        this.storageSize = storageSize;
        System.out.println(storageSize + "GB SSD will be used");
    }

    public void getType() {
        System.out.println("SSD");
    }

    @Override
    public String toString() {
        return storageSize + "GB Solid State Drive";
    }
}
package com.adevguide.java.designpatterns.abstractfactory;

public class DellProcessor implements Processor {

    private String storage;

    public DellProcessor() {

        System.out.println("AMD Processor will be used for Dell Laptop");
    }

    // This method will attach Storage Object with Processor
    public void attachStorage(Storage storage) {
        this.storage = storage.toString();
        System.out.println(storage + " is attached to Dell Laptop");
    }

    public void printSpecs() {
        System.out.println(this.toString());

    }

    @Override
    public String toString() {
        return "DellProcessor is created using AMD Processor and " + this.storage;
    }

}
package com.adevguide.java.designpatterns.abstractfactory;

public class DellStorage implements Storage {

    private int storageSize;

    public DellStorage(int storageSize) {
        this.storageSize = storageSize;
        System.out.println(storageSize + "GB HDD will be used");
    }

    public void getType() {
        System.out.println("HDD");

    }

    @Override
    public String toString() {
        return storageSize + "GB Hard Disk";
    }

}

This concrete class has an implementation of the AbstractProduct interface along with some class-specific logic.

Abstract Factory

LaptopFactory is an interface acting as an Abstract Factory in our example. It contains declaration of common methods.

package com.adevguide.java.designpatterns.abstractfactory;

public interface LaptopFactory {

    Processor createProcessor();

    Storage createStorage();
}

Concrete Factory

AppleLaptop and DellLaptop are Concrete Factory class implementing LaptopFactory.

package com.adevguide.java.designpatterns.abstractfactory;

public class AppleLaptop implements LaptopFactory {

    private int storageSize;

    public AppleLaptop(int storageSize) {
        this.storageSize = storageSize;
    }

    public Processor createProcessor() {
        return new AppleProcessor();
    }

    public Storage createStorage() {
        return new AppleStorage(storageSize);
    }

}

 

package com.adevguide.java.designpatterns.abstractfactory;

public class DellLaptop implements LaptopFactory {
    private int storageSize;
    public DellLaptop(int storageSize) {
        this.storageSize=storageSize;
    }
    
    public Processor createProcessor() {
        return new DellProcessor();
    }

    public Storage createStorage() {
        return new DellStorage(storageSize);
    }

}

 

Client

The client will act as a Client class that will invoke Abstract Factory class.

package com.adevguide.java.designpatterns.abstractfactory;


public class Client {

    public static void main(String[] args) {

        Processor dellProcessor = createLaptop(new DellLaptop(1024));
        dellProcessor.printSpecs();
        System.out.println("*****************************************");
        Processor appleProcessor = createLaptop(new AppleLaptop(512));
        appleProcessor.printSpecs();

    }

    // config method that will create an instance of Processor with passed abstract class object
    public static Processor createLaptop(LaptopFactory laptopFactory) {
        Processor processor = laptopFactory.createProcessor();
        Storage storage = laptopFactory.createStorage();
        processor.attachStorage(storage);
        return processor;

    }

}

OUTPUT

AMD Processor will be used for Dell Laptop
1024GB HDD will be used
1024GB Hard Disk is attached to Dell Laptop
DellProcessor is created using AMD Processor and 1024GB Hard Disk
*****************************************
Intel Processor will be used for Apple Laptop
512GB SSD will be used
512GB Solid State Drive is attached to Apple Laptop
AppleProcessor is created using Intel Processor and 512GB Solid State Drive

 

createLaptop(LaptopFactory laptopFactory) accepts ConcreteFactory object i.e AppleLaptop or DellLaptop. Both these objects accepts Storage Size as a constructor parameter.

This ConcreteFactory class has a product-specific implementation of two methods createProcessor() and createStorage() .

These implemented methods return a final product-specific object of Processor and Storage.

Let’s walk through the flow again:

Processor dellProcessor = createLaptop(new DellLaptop(1024));

The AbstractFactory class LaptopFactory is the one that determines the actual type of the concrete object DellProcessor and creates it, but it returns an abstract pointer Processor to the concrete object just created.

This determines the behavior of the client that asks the factory to create an object of a certain abstract type and to return the abstract pointer to it, keeping the client from knowing anything about the actual creation of the object.

The fact that the factory returns an abstract pointer Processor to the created object means that the client doesn’t have knowledge of the object’s type DellProcessor. This implies that there is no need for including any class declarations relating to the concrete type, the client dealing at all times with the abstract type.

The objects of the concrete type DellProcessor, created by the factory LaptopFactory, are accessed by the client only through the abstract interface DellFactory.

Factory Design Pattern Java Simplified [Simple Real World Example]

Another benefit of creating objects this way is that when the addition of new concrete types is needed, all we have to do is modify the client code and make it use a different factory, which is far easier than instantiating a new type, which requires changing the code wherever a new object is created.

When to use Abstract Factory Design Method?

  1. When the client doesn’t need to know how the final product is actually created.
  2. When the system demands the creation of a library of products, for which only interfaces are required, not the implementation.
  3. When the system needs to be configured with one of a multiple-family of objects.

Advantages of Abstract Factory Design Method

  1. Abstract Factory pattern provides an approach to code for interface rather than implementation. It isolates the client code from concrete (implementation) classes.
  2. Abstract Factory pattern is a “factory of factories” and can be easily extended to accommodate more products, for example, we can add another sub-class AsusLaptop and a factory AsusProcessor and AsusStorage.
  3. Abstract Factory pattern is robust and avoids the conditional logic of Factory pattern.
  4. It eases the exchanging of object families and promotes consistency among objects.

Microsoft Test Dumps

Pitfalls Of Abstract Factory Design Method

  1. This is a lot more complex to implement than the factory method.
  2. If a product needs to implement new functionality, All concrete products will require to make the change.
  3. It isn’t easy to visualize the need for this pattern at the start of system design and also very complex to adapt this into the existing system.
  4. Abstract Factory Design Method makes sense only when the system has “Product Families“.

 

Example of Abstract Factory Design Method

  • javax.xml.parsers.DocumentBuilderFactory#newInstance()
  • javax.xml.transform.TransformerFactory#newInstance()
  • javax.xml.xpath.XPathFactory#newInstance()

Abstract Factory Design Method Source Code

Source Code for this tutorial can be found in our GitHub Repository

GitHub Source Code

References

https://www.oodesign.com/abstract-factory-pattern.html