Abstract Factory

Intent

Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.

Problem

Imagine that you are creating a simulator of a furniture shop. Your code consists of:

  1. Family of related products, say: Chair + Sofa + CoffeeTable.

  2. Several variants of this family. For example, products Chair + Sofa + CoffeeTable available in these variants: IKEA, VictorianStyle, ArtDeco.

You need a way to create individual furniture objects so that they match other objects of the same family. Customers get quite frustrated when receive non-matching furniture.

Also, you do not want to change existing code when adding new products or families of products to the program. Furniture vendors update their catalogs very often, and you do not want to change the core code each time it happens.

Solution

The first thing that Abstract Factory pattern suggests is to go over all distinct products and force their variants to follow common interfaces. For example, all chair variants must follow the Chair interface; all coffee tables must implement the CoffeeTable interface, etc.

The second step is to create the AbstractFactory, a base interface that declares methods for creating all products that make a product family (i.e. createChair, createSofa and createCoffeeTable). The important thing here is to make these methods to return abstract product types represented by interfaces we extracted previously: Chair, Sofa, CoffeeTable, etc.

The third step is to implement concrete factories. Factories are classes that return products of a particular kind. For example, IKEAFactory, will only return IKEAChair, IKEASofa and IKEACoffeeTable objects. All factories must follow the AbstractFactory interface while creating the same variety of products.

Client code has to work with factories and products only through their abstract interfaces. This way you can alter the type of products used in client code by passing it a different factory object.

So, when client code asks a factory to produce a chair, it must not be aware of the factory's concrete class. It must not be aware of the concrete class of chair it will get either. Whether it will be a modern IKEA model or a Victorian style chair, it must work with all chairs in the same way, using the abstract Chair interface. The thing that the client code will know is that the resulting chair implements the sit method, declared in the interface. It also knows that whichever chair will be returned, it will match the type of sofa and coffee table, produced by the same factory.

Okay, but who creates the actual factory objects? Usually, the program creates a concrete factory object at initialization stage, and the factory type is picked depending on the configuration or environment.

Structure

Abstract Factory design pattern
  1. Abstract products declare interfaces for all distinct products that make a product family. Normally, there should be several different product interfaces.

  2. Concrete products implement different abstract product interfaces. Sets of concrete products implemented similarly represent different variants of a product family.

  3. Abstract factory declares the interface for creating all products of a family.

  4. Concrete factories implement creation methods of the abstract factory. Each concrete factory corresponds to the specific variant of a product family.

  5. Although concrete factories instantiate concrete products, signatures of their creation methods must declare corresponding abstract products as a return type. This way the client code which uses a factory will not get coupled to the specific variant of products. It will be able to work with any factory/product variant using the abstract interfaces.

Pseudocode

This example illustrates how the Abstract Factory pattern can be used to create cross-platform UI elements without coupling client code to concrete UI classes.

Client code requests various UI elements from a factory. The concrete type of returned elements depends on the type of the factory, passed to the client code. Client code works with elements using abstract interfaces. As long as it uses the same factory object, all its products should be compatible.

The Abstract Factory design pattern makes client code independent from concrete classes of UI elements. In addition, you do not have to touch the existing code, when a new UI variation is requested (for instance, implementing Linux UI elements). You just need to create a new factory subclass that returns UI elements of a new type.

// This pattern assumes that you have several families of products, structured
// into separate class hierarchies (Button/Checkbox). All products of the same
// family must follow the common interface.
interface Button is
    method paint()

// All products families have the same varieties (macOS/Windows).
class WinButton implementing Button is
    method paint() is
        Render a button in Windows style

class MacButton implementing Button is
    method paint() is
        Render a button in macOS style


interface Checkbox is
    method paint()

class WinCheckbox implementing Checkbox is
    method paint() is
        Render a checkbox in Windows style

class MacCheckbox implementing Checkbox is
    method paint() is
        Render a checkbox in macOS style


// Abstract factory knows about all (abstract) product types.
interface GUIFactory is
    method createButton():Button
    method createCheckbox():Checkbox


// Each concrete factory extends basic factory and responsible for creating
// products of a single variety.
class WinFactory implementing GUIFactory is
    method createButton():Button is
        return new WinButton
    method createCheckbox():Checkbox is
        return new WinCheckbox

// Although concrete factories create the concrete products, they still return
// them with the abstract type. This fact makes factories interchangeable.
class MacFactory implementing GUIFactory is
    method createButton():Button is
        return new MacButton
    method createCheckbox():Checkbox is
        return new MacCheckbox


// Factory users do not care which concrete factory they use since they work
// with// factories and products through abstract interfaces.
class Application is
    private field button: Button
    constructor Application(factory: GUIFactory) is
        this.factory = factory
    method createUI() is
        this.button = factory.createButton()
    method paint() is
        button.paint()


// Application picks the factory type and creates it in run time (usually at
// initialization stage), depending on the configuration or
// environment variables.
class ApplicationConfigurator is
    method main() is
        Read the configuration file
        If the OS specified in the configuration file is Windows, then
            Construct a WinFactory
            Construct an Application with WinFactory
        else
            Construct an MacFactory
            Construct an Application with MacFactory

Applicability

When a business logic must work with different variants of products from some product family, but you do not want it to depend on concrete product classes (or if they are unknown beforehand).

Abstract Factory hides from client code information about classes of products that it creates. Client code can work with any product created by any factory as long as it works with them using the abstract interfaces.

When a class has multiple Factory Methods that blur its main responsibility.

In a well-designed program each class must be responsible only for one thing. When a class deals with multiple product types, it may be worth replacing multiple factory methods with a stand-alone abstract factory.

How to Implement

  1. Map out a matrix of distinct products versus variants of the same product.

  2. Create abstract interfaces for all distinct product types and make all concrete products follow these interfaces.

  3. Declare the abstract factory interface. This interface should list creation methods for all distinct types of products.

  4. Implement separate factory classes for each variant of the product family.

  5. Create a factory initialization code somewhere in client code. It should pick the type and create a concrete factory depending on the configuration or current environment.

  6. In the client code, replace all product constructor calls with calls to the creation method in the factory object.

Pros and Cons

  • Follows the Open/Closed Principle.
  • Allows building families of product objects and guarantees their compatibility.
  • Avoids tight coupling between concrete products and code that uses them.
  • Divides responsibilities between multiple classes.
  • Increases overall code complexity by creating multiple additional classes.

Relations with Other Patterns

  • Often, designs start out using Factory Method (less complicated, more customizable via subclasses) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, but more complex) as the designer discovers where more flexibility is needed.

  • Builder focuses on constructing a complex object step by step. Abstract Factory creates families of product objects (either simple or complex). Builder returns the product as a final step, but the Abstract Factory returns the result immediately.

  • Abstract Factory classes are often implemented with Factory Methods, but they can also be implemented using Prototype.

  • Abstract Factory can be used as an alternative to Facade to hide platform-specific classes.

  • Abstract Factory can be used along with a Bridge pattern. It's useful when the "interface" part of the Bridge can work only with a particular "implementation". In this case, factory can encapsulate these relations and hide the complexity from a client.

  • Abstract Factory, Builder and Prototype can be implemented as Singletons.

Implementations in Different Programming Languages

Java

Extra Content

  • If you can not figure out the difference between various factory patterns and concepts, then read our Factory Comparison guide.