Abstract Factory
Produce whole families of related objects through one interface, so the client never picks a concrete class and never gets a mismatched set.
The problem
You are building a furniture shop simulator. There is a family of related products - chair, sofa, coffee table - and several variants of that family: Modern, Victorian, ArtDeco. You need individual objects that match each other, because customers get remarkably cross when a Modern sofa turns up beside Victorian chairs.
Two problems compound. Nothing in the type system stops you from mixing variants, and vendors refresh their catalogs constantly, so every new family means surgery on core code.
The solution
First, declare an interface for each distinct product in the family: Chair, Sofa,
CoffeeTable. Every variant of a chair implements Chair, and so on down the list.
Then declare the abstract factory itself: an interface with a creation method per
product, each returning the abstract type. For every variant, write one concrete factory
that implements the lot. VictorianFactory produces VictorianChair and VictorianSofa
and literally cannot produce anything else. The client holds a FurnitureFactory reference
and asks it for furniture, and because all the answers come from the same instance, they
match by construction.
- 1At startup the app reads a setting and instantiates exactly one concrete factory. This is the only concrete decision in the program.
- 2The factory is injected into the client, which stores it as the abstract FurnitureFactory type.
- 3The client asks for a chair. It does not ask for a Victorian chair; it does not know that word.
- 4Inside the method a concrete product is built, but the signature still says it returns Chair.
- 5The next request goes to the same factory instance, which is what makes the sofa guaranteed to match the chair.
- 6The client uses the product through its abstract interface. Switch to ModernFactory tomorrow and not one line here changes.
Structure
Think of it as a matrix: product types down one axis, variants across the other. The abstract product interfaces are the rows, the concrete factories are the columns, and each factory fills in one column completely.
Code
Same example three ways: a showroom that furnishes a matching room without knowing which century it is decorating.
When to use it
- Your code works with several families of related products and you do not want it bound to their concrete classes, either because the classes are not known yet or because you want room to add more.
- A class has accumulated a set of factory methods that are starting to blur its actual responsibility. Extracting them into a standalone factory is the natural next move.
Pitfalls
- Class inflation. A matrix of products and variants means a lot of interfaces and classes. Two products and two variants is already eight types. Make sure the compatibility guarantee is worth the paperwork.
- The rigid product axis. Adding a product type is a breaking change to the factory interface and to every implementation of it. Design that axis before you commit.
- Half-abstract clients. One stray cast to a concrete product and the variant leaks out of the factory and into code that was supposed to be ignorant of it.
Don't confuse it with
- Factory Method. Abstract Factory is usually built out of factory methods; the difference is scope. One method for one product versus one object for a whole family.
- Builder. Abstract Factory returns the product immediately. Builder deliberately spends several calls assembling one complex object before you fetch it.
- Facade. When your only goal is hiding how subsystem objects get created, a facade may be the lighter answer. Abstract Factory earns its keep when variants are the point.
Check yourself
What does an Abstract Factory guarantee that a pile of separate factory methods does not?