Abstract Factory
Lets you produce families of related objects without specifying their concrete classes.
classDiagram
class AbstractFactory {
<<interface>>
+createProductA() ProductA
+createProductB() ProductB
}
class ConcreteFactory1 {
+createProductA() ProductA
+createProductB() ProductB
}
class ConcreteFactory2 {
+createProductA() ProductA
+createProductB() ProductB
}
class ProductA {
<<interface>>
}
class ConcreteProductA1
class ConcreteProductA2
class ProductB {
<<interface>>
}
class ConcreteProductB1
class ConcreteProductB2
AbstractFactory <|.. ConcreteFactory1
AbstractFactory <|.. ConcreteFactory2
ProductA <|.. ConcreteProductA1
ProductA <|.. ConcreteProductA2
ProductB <|.. ConcreteProductB1
ProductB <|.. ConcreteProductB2
ConcreteFactory1 ..> ConcreteProductA1
ConcreteFactory1 ..> ConcreteProductB1
ConcreteFactory2 ..> ConcreteProductA2
ConcreteFactory2 ..> ConcreteProductB2
When to use
Use when your code needs to work with various families of related products, but you don’t want it to depend on the concrete classes of those products—they might be unknown beforehand or you simply want to allow for future extensibility.
Explanation
Problem
Imagine you’re creating a furniture shop simulator. Your code consists of classes that represent:
- A family of related products, say:
Chair+Sofa+CoffeeTable. - Several variants of this family. For example,
Modern,Victorian,ArtDeco.
You need a way to create individual furniture objects so that they match other objects of the same family. Customers get quite mad when they receive a non-matching furniture. Also, you don’t want to change existing code when adding new products or families of products.
Solution
The Abstract Factory pattern suggests explicitly declaring interfaces for each distinct product in the product family (e.g., chair, sofa or coffee table). Then, you make all variants of products follow those interfaces. For example, all chair variants can implement the Chair interface; all sofa variants can implement the Sofa interface, and so on.
The next step is to declare the AbstractFactory—an interface with a list of creation methods for all products that are part of the product family (for example, createChair, createSofa and createCoffeeTable). These methods must return abstract product types represented by the interfaces we extracted previously: Chair, Sofa, CoffeeTable and so on.
Real world problem
- Cross-Platform UI: A UI toolkit needs to create components (Buttons, Checkboxes, Sliders) that look correct on different Operating Systems (Windows, macOS, Linux). A
WindowsFactorycreatesWindowsButtonandWindowsCheckbox. - Database Connectors: Accessing different databases (MySQL, PostgreSQL, SQLite). A
MySQLFactorycreatesMySQLConnection,MySQLCommand. - Theming: An app supports multiple themes (Light, Dark, HighContrast). A
DarkThemeFactorycreatesDarkButton,DarkWindow.
Pros and Cons
| Pros | Cons |
|---|---|
| - Compatibility Guarantee: You can be sure that the products you’re getting from a factory are compatible with each other. - Avoid Tight Coupling: You avoid tight coupling between concrete products and client code. - Single Responsibility Principle: You can extract the product creation code into one place, making the code easier to support. - Open/Closed Principle: You can introduce new variants of products without breaking existing client code. |
- Complexity: The code may become identical to the implementation of the Factory Method pattern, or become much more complicated than it needs to be. Requires many new interfaces and classes. |
Comparison
- Factory Method: Abstract Factory creates “families” of products. Factory Method creates one product.
- Builder: Builder constructs a complex object step by step. Abstract Factory creates families of objects.
- Prototype: Abstract Factory is often implemented with a set of Factory Methods. Prototype can also be used in Abstract Factory (storing prototypes to clone).
Code example
Typescript
Php