We're working on a substantial update for the whole design patterns section that should be ready by the end of September. Until then, please sorry for all embarrassing typos and errors you might encounter here and there.
Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.
Imagine that you are creating a simulator of a furniture shop. Your code consists of:
Family of related products, say:
Several variants of this family. For example, products
CoffeeTableavailable in these variants:
You need a way to create individual furniture objects so that they match other objects of the same family. Customers get quite frustrated when they 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.
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.
createCoffeeTable). The important thing here is to make these methods to return abstract product types represented by interfaces we extracted previously:
The third step is to implement concrete factories. Factories are classes that return products of a particular kind. For example,
IKEAFactory, will only return
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.
Abstract products declare interfaces for all distinct products that make a product family. Normally, there should be several different product interfaces.
Concrete products implement different abstract product interfaces. Sets of concrete products implemented similarly represent different variants of a product family.
Abstract factory declares the interface for creating all products of a family.
Concrete factories implement creation methods of the abstract factory. Each concrete factory corresponds to the specific variant of a product family.
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.
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.
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
Map out a matrix of distinct products versus variants of the same product.
Create abstract interfaces for all distinct product types and make all concrete products follow these interfaces.
Declare the abstract factory interface. This interface should list creation methods for all distinct types of products.
Implement separate factory classes for each variant of the product family.
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.
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 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.
- If you can not figure out the difference between various factory patterns and concepts, then read our Factory Comparison guide.