0 XP · 0 scenes

Abstract Factory

Create whole families of matching objects
The problem

The UI code creates a button from one theme, a checkbox from another and a menu from a third by hand.

The idea

Give each family one factory with a method per product: createButton(), createCheckbox().

Reach for it when

Products come in families that must be used together

1

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.

2

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.

✗ Before
render_dialog()button = DarkButton()checkbox = LightCheckbox() ← mismatchDarkButtonLightCheckbox
  • creates
The caller creates each widget itself, so a Dark button can end up next to a Light checkbox.
Reach for it when
  • 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
3

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.

✓ After
render_dialog()«interface»UiFactorycreate_button()create_checkbox()DarkFactoryLightFactoryDarkButtonDarkCheckboxLightButtonLightCheckboxany factory
  • implements
  • calls / uses
  • creates
One factory makes a whole matching family. Pick the factory and the look is consistent.

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

  1. 1List the product kinds (button, checkbox).
  2. 2Write an interface per kind.
  3. 3Write one factory interface with a method per kind.
  4. 4Implement one factory per family.
4

Watch it run

Step through the calls. Tap an arrow to jump to it.

ClientDarkFactoryDarkButtonDarkCheckbox1create_button()2DarkButton3create_checkbox()4DarkCheckbox5draw()6draw()
Step 1/6

The client got a DarkFactory. It asks for a button.

create_button()
5

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.
6

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.

Confidence