← Back to PatternPip

FACTORY METHOD / THE IDEA IN A MINUTE

Deliver the package.
Let the service choose the vehicle.

A delivery company sends packages by road or sea. The dispatch process is the same; the vehicle it creates is different.

RoadDelivery creates a Truck. SeaDelivery creates a Ship. Both inherit the same process: check the destination, create transport, and ask it to deliver. Factory Method is the creation step each service can override.

What is created?
A vehicle object: a Truck, Ship or Plane.
What stays shared?
Check the destination, create transport, then deliver the package.
Who chooses the vehicle?
RoadDelivery creates a Truck. SeaDelivery creates a Ship. Each overrides the same creation method.

THE STRUCTURE / FOUR ROLES

The delivery service creates. The vehicle delivers.

The creator is the delivery service. The product is the vehicle object it creates. A Truck or Ship does the delivery; the shared dispatch process coordinates the work.

Choose road or sea

Switch delivery types. The shared dispatch process and Transport interface stay the same.

01 / CREATORShared

DeliveryService

Owns dispatch(), the workflow that uses a Transport.

  1. Check the destination
  2. Call this.createTransport()
  3. Call transport.deliver(shipment)
The factory methodcreateTransport(): TransportDeclared here. Overridden by a subclass.

02 / PRODUCT INTERFACEShared

Transport

Promises the operation every vehicle must support.

deliver(shipment): DeliveryReceipt

DeliveryService can use any vehicle that honors this contract.

03 / CONCRETE CREATORVaries

RoadDelivery

Inherits DeliveryService.dispatch(). Overrides createTransport() to return a Truck.

The creation choice lives here.

04 / CONCRETE PRODUCTVaries

Truck

Implements Transport. Its deliver(shipment) method drives on roads.

The vehicle-specific delivery lives here.

Read the arrows as relationships: the concrete creator inherits the workflow, the concrete vehicle implements the product interface, and the creator’s factory method constructs that vehicle.

RoadDelivery → Truck. The pair changes; DeliveryService.dispatch() and Transport stay shared.

Now follow the creation trace below: choose a service and see how the workflow gets its vehicle.

FOLLOW THE CREATION

One workflow. Follow the creation detour.

Try it yourself

Step into the code. Pause at the creation hook, follow the subclass override, then bring its object back to the shared workflow.

const service = new RoadDelivery()
service.dispatch(shipment)
One service instance · inherits dispatch()

STEP 1 / 8

Choose service

Setup creates a RoadDelivery service. It inherits dispatch() from DeliveryService. No Truck exists yet.

  1. 1Choose service
  2. 2Enter workflow
  3. 3Call the hook
  4. 4Enter override
  5. 5Create object
  6. 6Return object
  7. 7Use object
  8. 8See the benefit
SHARED WORKFLOWUnchanged

DeliveryService.dispatch()

Inherited by RoadDelivery. Same method for every service.

dispatch(input: Shipment): DeliveryReceipt {
  const shipment = validateShipment(input)
  const transport = this.createTransport()
  return transport.deliver(shipment)
}
this.createTransport() → subclass override
SUBCLASS OVERRIDE

RoadDelivery

Extends DeliveryService. Changes creation; inherits the rest.

class RoadDelivery extends DeliveryService {
  protected createTransport(): Transport {
    const transport = new Truck()
    return transport
  }
}

Only createTransport() is overridden.

THE PRODUCT · A SOFTWARE OBJECT

No vehicle object yet

The vehicle appears only when its constructor runs. Watch the creation step.

NOW TEST THE BENEFIT

A new request: deliver by air.

Add a vehicle without editing the inherited dispatch() method. Then trace the new service through the same code above.

Step 1 of 8. Setup creates a RoadDelivery service. It inherits dispatch() from DeliveryService. No Truck exists yet.

This is a guided replay of a real local model run. Each step waits for you; highlighted excerpts omit tracing callbacks and receipt bookkeeping. The complete source is in the lesson and quick reference.

A useful extension point.

A framework already owns a workflow, but applications need to supply different kinds of objects within it. Each product supports the same interface, so the workflow can use it without knowing its concrete class.

Keep the cost in view.

Each variation adds a subclass. For a small, stable set of delivery types, a simple conditional or factory function may be clearer. If you only need to provide an existing object, constructor injection may be enough.

Choose your next step.