0 XP · 0 scenes

Factory Method

Let a method decide which class to create
The problem

The delivery code does if kind == "road": Truck() elif kind == "sea": Ship().

The idea

Move creation into one overridable method, createTransport().

Reach for it when

The code that uses an object should not know its exact class

1

The picture from life

At a pizza shop you say "one veg pizza". You do not pick the dough, the sauce or the oven; the kitchen decides how it is made. If the shop opens a new branch with a different oven, you still order the same way and the pizza arrives.

2

The problem

What goes wrong when you do not use it.

The delivery code does if kind == "road": Truck() elif kind == "sea": Ship(). Adding air transport means editing that code and every other place that repeats the same ladder.

✗ Before
deliver(kind)if kind == 'road': Truck()elif kind == 'sea': Ship()# new vehicle = edit hereTruckShip
  • creates
The caller picks the class with if/else and knows every concrete class.
Reach for it when
  • The code that uses an object should not know its exact class
  • Subclasses should choose what to create
  • You expect new kinds to appear
3

The idea

How the pattern fixes it.

Move creation into one overridable method, createTransport(). The shared planning code calls it and uses whatever comes back. Each subclass of the creator returns its own product.

✓ After
«abstract»Logisticsplan_delivery()create_transport()RoadLogisticscreate_transport()SeaLogisticscreate_transport()Truckdeliver()Shipdeliver()
  • extends (is a)
  • creates
The base class has the plan. Each subclass decides which vehicle to create.

Who is who

Transport
The product interface: deliver().
Truck, Ship
Concrete products.
Logistics
The creator. Has planDelivery() that calls the factory method.
RoadLogistics, SeaLogistics
Override createTransport() to return Truck or Ship.

Build it in steps

  1. 1Define the product interface.
  2. 2Add an abstract createTransport() to the creator.
  3. 3Let the shared method call it.
  4. 4Subclass the creator for every kind.
4

Watch it run

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

ClientSeaLogisticsShip1plan_delivery()2create_transport()3Ship()4deliver()5'ship delivers'6'ship delivers'
Step 1/6

The client asks for a delivery. It never names Ship.

plan_delivery()
5

The code

Python and Java. Try writing the classes yourself from the diagram first.

class Truck:
    def deliver(self):
        return "truck delivers"


class Ship:
    def deliver(self):
        return "ship delivers"


class Logistics:
    def create_transport(self):               # the factory method
        raise NotImplementedError

    def plan_delivery(self):
        return self.create_transport().deliver()


class RoadLogistics(Logistics):
    def create_transport(self):
        return Truck()


class SeaLogistics(Logistics):
    def create_transport(self):
        return Ship()


def demo():
    return [RoadLogistics().plan_delivery(), SeaLogistics().plan_delivery()]

What you gain

  • The creator never depends on concrete products
  • Adding a product means adding a class, not editing a ladder

What it costs

  • A new subclass per product can feel heavy
  • For two or three fixed kinds a simple function or map is enough

You have already met it in

  • Calendar.getInstance() and NumberFormat.getInstance() in Java
  • Frameworks that create your view or controller for you

Often mixed up with

  • Abstract FactoryFactory Method makes one product through inheritance; Abstract Factory makes a whole matching family of products.
  • BuilderFactory Method picks which class; Builder assembles one complex object step by step.
6

Make it stick

Write a NotificationSender with a createChannel() factory method and subclasses for Email and SMS. Add Push without editing the shared send() code.

Confidence