Abstract Factory
The UI code creates a button from one theme, a checkbox from another and a menu from a third by hand.
Give each family one factory with a method per product: createButton(), createCheckbox().
Products come in families that must be used together
The picture from life
A furniture showroom sells ready "collections": Modern or Victorian. When you pick the Modern collection you get a modern chair, a modern sofa and a modern table, all matching. Nobody ends up with a Victorian sofa next to a modern chair.
The problem
What goes wrong when you do not use it.
The UI code creates a button from one theme, a checkbox from another and a menu from a third by hand. Sooner or later a dark button sits on a light dialog. Nothing stops the mismatch.
- creates
- Products come in families that must be used together
- You switch the whole family at once (theme, OS, database vendor)
- The client must not know concrete classes
The idea
How the pattern fixes it.
Give each family one factory with a method per product: createButton(), createCheckbox(). The client receives a single factory and builds everything from it, so everything matches automatically.
- implements
- calls / uses
- creates
Who is who
- UiFactory (interface)
- Declares createButton() and createCheckbox().
- DarkFactory, LightFactory
- Each returns products of its own theme.
- Button, Checkbox
- Product interfaces with one implementation per theme.
- Client
- Takes a UiFactory and never names a concrete class.
Build it in steps
- 1List the product kinds (button, checkbox).
- 2Write an interface per kind.
- 3Write one factory interface with a method per kind.
- 4Implement one factory per family.
Watch it run
Step through the calls. Tap an arrow to jump to it.
The client got a DarkFactory. It asks for a button.
create_button()The code
Python and Java. Try writing the classes yourself from the diagram first.
class DarkButton:
def draw(self):
return "dark button"
class LightButton:
def draw(self):
return "light button"
class DarkCheckbox:
def draw(self):
return "dark checkbox"
class LightCheckbox:
def draw(self):
return "light checkbox"
class DarkFactory:
def create_button(self):
return DarkButton()
def create_checkbox(self):
return DarkCheckbox()
class LightFactory:
def create_button(self):
return LightButton()
def create_checkbox(self):
return LightCheckbox()
def render_dialog(factory): # knows no concrete class
return [factory.create_button().draw(), factory.create_checkbox().draw()]
def demo():
return render_dialog(DarkFactory()), render_dialog(LightFactory())What you gain
- Products from one family always match
- Switch the whole family by swapping one object
What it costs
- Many classes: products times families
- Adding a new product kind means touching every factory
You have already met it in
- Cross-platform UI toolkits (one factory per OS)
- Database drivers that return a matching Connection, Statement and ResultSet
Often mixed up with
- Factory MethodAbstract Factory is a group of factory methods working together for one family.
- BuilderBuilder constructs one object in steps; Abstract Factory returns finished objects of a family at once.
Make it stick
Build a game with a MedievalFactory and a SciFiFactory that each create a Weapon and an Enemy. Make sure a sci-fi enemy never meets a medieval weapon.