Abstract Factory

Intent

Allows producing families of related or dependent objects without specifying their concrete classes.

Problem

Imagine that you're creating a simulator of a furniture shop. Your code has:

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

  2. Several variants of these families. For example, products Chair + Sofa + CoffeeTable have following variants: IKEA, VictorianStyle, ArtDeco.

You need a way to create product objects so that:

  1. They fit other objects of the same family.

    Customers get frustrated when they get non-matching furniture.

  2. It could be easy to add new product or family of products without changing existing code.

    You may want to change the furniture vendors pretty often, but they offer different furniture sets all the time. You wouldn't like to change the core code each time it happens.

Solution

The first thing that Abstract Factory pattern suggest is to gather product families into separate class hierarchies with common interfaces. Now all kinds of chairs will get a common interface Chair; all coffee tables will implement CoffeeTable interface, etc.

The second step is to create a base interface for all factories—the AbstractFactory. It will define multiple methods for creating all distinct product types (i.e. createChair, createSofa and createCoffeeTable). Note that signatures of these methods should return abstract product types: Chair, Sofa, CoffeeTable, etc.

The third step is to implement concrete factories. Factories are classes that return products of the one particular kind, for example, IKEAFactory, VictorianStyleFactory and ArtDecoFactory. All factories follow the AbstractFactory interface, but each factory creates certain variant of products.

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

So, when a client code asks a factory to produce a chair, it shouldn't know the concrete type of a factory. Therefore, it won't know which kind of chair it'll get—the modern IKEA model or a Victorian style chair. It shouldn't care either since it works with chairs using their abstract interfaces. It expects that a chair has a method sit and that it matches 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 pattern structure
  1. Abstract products define interface for all distinct products of a single product family. Normally, there should be several different product interfaces.

    The abstract factory has creational methods corresponding to each abstract product.

  2. Concrete products implement the abstract product interface. They are returned by creational methods of concrete factories.

    Each concrete product corresponds to a particular type of a concrete factory.

  3. Abstract factory defines the interface for creating products, common to all concrete factories.

    Here you must define creational methods for producing all abstract product types.

  4. Concrete factories implement creational methods of the abstract factory. Each concrete factory should correspond to a specific products variant.

    Although creational methods of a factory instantiate concrete products inside, their signatures don't say much about a product variant that will be returned—they all seem to return abstract products. This way client code won't be coupled to the specific products and factories. It will be able to work with any factory/product variant.

    Usually, a program needs just a single instance of a concrete factory.

Pseudocode

This example illustrates how Abstract Factory can be used to create cross-platform UI elements without tying client code to concrete UI classes. Client code requests various UI elements from a factory of a particular type. The factory object decides what variation of elements to return. Client code works with them using abstract interfaces. As long as the client code uses a single 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 don't have to touch the existing code, when a new UI variation is needed (for instance, Linux elements). You just need to create a new factory subclass that would return 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 have the common interface.
interface Button is
    method paint()

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

class OSXButton implementing Button is
    method paint() is
        Render a button in a Mac OS X style


interface Checkbox is
    method paint()

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

class OSXCheckbox implementing Checkbox is
    method paint() is
        Render a checkbox in a Mac OS X 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 OSXFactory implementing GUIFactory is
    method createButton():Button is
        return new OSXButton
    method createCheckbox():Checkbox is
        return new OSXCheckbox


// Factory users don't care which concrete factory they use since they work with
// factories and products through abstract interfaces.
class Application is
    constructor Application(factory: GUIFactory) is
        Button button = factory.createButton()
        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 OSXFactory
            Construct an Application with OSXFactory

Applicability

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

Abstract Factory hides from a client code the concrete product classes it instantiates. Client code can work with any product created by any factory as long as it works with them using the abstract interfaces.

Instead of rewriting client code, one could extend the product hierarchy, create a new factory class to instantiate these products and pass it to client code.

When Factory Method had already been applied to the program classes, and there is a requirement to add new product types.

In a well-designed program each class is responsible only for one thing. Multiple factory methods in a client class can blur its main responsibility. In this case, it makes sense to extract factory methods into a separate class hierarchy and turn the Factory Method into 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 product classes implementing these interfaces.

  3. Define the abstract factory interface common for all concrete factories. This interface should define creational methods for all abstract products types.

  4. Create concrete factory classes. The number of these classes should match the number of all product variants. A concrete factory class should depend on the abstract factory interface and on the concrete product classes of the same variant.

  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 creational 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't figure out the difference between Factories, Factory Method & Abstract Factory patterns, then read our Factory Comparison guide.