This is the 4th post in a series on design patterns.
Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.
If you were creating a furniture shop simulator, how would you design it? There are classes that represent:
- A group of related products, such as bed + sofa + chair + table.
- In this family, for example, Bed + Sofa + Chair + Table are available in three variants: Modern, Vintage, and Victorian.
A way needs to be found to create individual furniture items (bed, sofa, chair, table) so that they match other objects of the same family (modern, vintage, Victorian). If you add new products or families of products to your software, you don’t want to change the existing code.
Abstract Factory Design Pattern
As a first step, Abstract Factory suggests explicitly declaring interfaces for each distinct product of the product family (bed, sofa, chair, and table). You can then make all variants of the products adhere to these interfaces. For instance, all bed variants can implement the Bed interface.
Next, the Abstract Factory interface is declared, which provides a list of creator methods for all products in the product family. Each of these methods must return an abstract type of product represented by the interface.
Then, we create a separate factory class for each variant of a product family based on the Abstract Factory interface. A factory is a class that returns products of a particular kind. ModernFurnitureFactory, for example, can only create ModernBed, ModernSofa, ModernChair, and ModernTable objects.
UML Class Diagram
Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
- Map out the types of products versus their variants.
- Define abstract interfaces for all product types. Make concrete product classes implement these interfaces.
- Create an abstract factory interface with a set of creator methods for all abstract products.
- Create concrete factory classes for each product variant.
- The factory initialization code should instantiate one of the concrete factory classes according to the configuration of the application. Pass this factory object to all classes that construct products.
Source Code Implementation
Declare interface for a set of distinct product but related products which make up a product family. For example, we have declared Bed and Chair products for furniture.
Concrete products are different implementations of abstract products grouped into variants. All abstract products (bed/chair) must be implemented in all variants (modern/vintage).
The Abstract Factory interface declares a set of methods for creating each abstract product.
Concrete factories implement the creator methods of abstract factories. Each concrete factory creates only a specific product variant.
Concrete factories create concrete products, but the signatures of their creation methods must return abstract products. So the client code that uses a factory is not tied to the specific variation it receives from a factory. As long as the client communicates with its objects via abstract interfaces, it can work with any concrete factory variant.
When To Apply Abstract Factory Design Pattern
- You can apply the Abstract Factory design pattern when you need to work with diverse families of related products, but you do not want your code to depend on the concrete classes for each, because they may not yet be known, or simply because you want to allow for future extensions.
Pros of Abstract Factory Design Pattern
- A factory ensures that the products you get are compatible with each other.
- You avoid tight coupling between client code and concrete products.
- Through the Single Responsibility Principle, you can consolidate product creation code in one place, making it easier to support.
- With the Open/Closed Principle, you can introduce new versions of products without breaking existing client code.