The factory pattern is a creational design pattern that allows the creation of certain Objects, called products, to be specialised based on whatever class needs that product, called concrete creators (you’ll see why below). It promotes reuse of code and allows products to be treated abstractly to the concrete creators.
Usecase
- When you have multiple classes that aggregate or compose specialised objects, but functionality between the specialised objects are very similar.
- When classes just need to create a class that falls under a category (e.g.
Category A
). The classes don’t care how the created class should be made, just that one needs to be made.
Properties
A factory pattern consists of two main structures - Creators and Products:
- Creators: These are the classes that instantiate products
- Base Creator: This is an abstract class which all other concrete creators inherit from. It could contain some Boolean checks to limit what can be created, or could just create a default product. This is ideally where the client accesses the factory.
- Concrete Creators: Inherits from the Base Creator, and create their own specialised product
- Products: These are the classes that do stuff, and are commonly linked in some manner
- Product Interface: If we have many, many types of products, it’s better to construct a product interface, which all specialised products must implement.
- Specialised Product: The actual product created by concrete creators
UML Class
UML class diagram of this pattern, along with explanation of methods/attributes.
classDiagram
direction TB
class BaseCreator {
+createProduct() IProduct
}
class CreatorA {
+createProduct() ProductA
}
class CreatorB {
+createProduct() ProductB
}
class IProduct {
+doStuff()
}
class ProductA
class ProductB
<<abstract>> BaseCreator
<<interface>> IProduct
BaseCreator <|-- CreatorA
BaseCreator <|-- CreatorB
IProduct <|.. ProductA
IProduct <|.. ProductB
BaseCreator ..> IProduct
createProduct()
: The so-called factory method. This is an abstract method could potentially return a defaultProduct
, but in most cases, is meant to be overridden by subclasses.doStuff()
: EveryProduct
would implement this method in same way, to allow common traits between all products.
Pros vs Cons
Pros
- Object creation is decoupled from functionality.
- Respects the Single Responsibility Principle: The factory is only responsible for the creation of objects, while the client code only needs to focus on functionality.
- Respects the Open-Closed Principle: The factor can easily be extended by adding new creators or objects, without breaking existing functionality.
- Supports Abstraction: The client code does not care about which product it receives, just that it needs one.
- Supports Delegation Through Association: The smaller, specialised concrete creator classes inherit from the base creator class, which delegates the task of actually creating the product to them.
Cons
- Not quite necessary for small codebases, could cause unnecessary bloat if used in places with very few ‘products’, or no need for conditional creation.