- 1) Implementation of Abstract Factory Design Pattern
- 2) Real World Example Implementation of Abstract Factory Design Pattern
- 3) When to use Abstract Factory Design Method?
- 4) Advantages of Abstract Factory Design Method
- 5) Pitfalls Of Abstract Factory Design Method
- 6) Example of Abstract Factory Design Method
- 7) Abstract Factory Design Method Source Code
- 8) References
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:
- Singleton Creational Design Pattern Java Explained [6 Code Example]
- Factory Design Pattern Java Simplified [Simple Real World Example]
- Factory Method Design Pattern Java Simple Detailed Examples
- Abstract Factory Design Pattern Java Real World Example
- Builder Design Pattern Java Real World Example
- Prototype Design Pattern Java Real World Example
Implementation of Abstract Factory Design Pattern
- Create an Abstract Factory as an Interface or an Abstract Class.
- Abstract factory defines abstract methods for creating products.
- Provide a concrete implementation of factory for each set of products.
- 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.
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.
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?
- When the client doesn’t need to know how the final product is actually created.
- When the system demands the creation of a library of products, for which only interfaces are required, not the implementation.
- When the system needs to be configured with one of a multiple-family of objects.
Advantages of Abstract Factory Design Method
- Abstract Factory pattern provides an approach to code for interface rather than implementation. It isolates the client code from concrete (implementation) classes.
- 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.
- Abstract Factory pattern is robust and avoids the conditional logic of Factory pattern.
- It eases the exchanging of object families and promotes consistency among objects.
Pitfalls Of Abstract Factory Design Method
- This is a lot more complex to implement than the factory method.
- If a product needs to implement new functionality, All concrete products will require to make the change.
- 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.
- 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