Abstract Factory is a creational design pattern that let you produce families of related or dependent objects without specifying their concrete classes.
Imagine that you're creating a simulator of a furniture shop. Your code has:
Family of related products, say:
Several variants of these families. For example, products
CoffeeTablehave following variants:
You need a way to create product objects so that:
They fit other objects of the same family.
Customers get frustrated when they get non-matching furniture.
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.
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.
createCoffeeTable). Note that signatures of these methods should return abstract product types:
The third step is to implement concrete factories. Factories are classes that return products of the one particular kind, for example,
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.
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.
Concrete products implement the abstract product interface. They are returned by Each concrete product corresponds to a particular type of a concrete factory.
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.
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.
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
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
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 product classes implementing these interfaces.
Define the abstract factory interface common for all concrete factories. This interface should define creational methods for all abstract products types.
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.
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 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 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.
Implementations in Different Programming Languages
- If you can't figure out the difference between various factory patterns and concepts, then read our Factory Comparison guide.