Factory Method Pattern
The Factory Method pattern defines an interface for creating objects but lets subclasses decide which class to instantiate. Use it when you want to decouple object creation from usage, making it easy to extend or swap implementations without changing client code.
Overview
The Factory Method pattern defines a method for creating an object, but defers the choice of concrete class to subclasses (or strategies). Client code talks to the base type and never names the concrete class, so adding a new variant becomes a matter of plugging in a new factory — no edits to the consumers.
When to use it
- Client code should not depend on the concrete class it instantiates.
- You expect new product variants over time and want each one isolated to its own factory.
- Object creation requires logic (config lookup, validation, registration) that doesn't belong in the consumer.
Example
interface Transport {
deliver(load: string): void;
}
class Truck implements Transport {
deliver(load: string) { console.log(`Truck delivering ${load}`); }
}
class Ship implements Transport {
deliver(load: string) { console.log(`Ship delivering ${load}`); }
}
abstract class Logistics {
abstract createTransport(): Transport;
planDelivery(load: string) {
const transport = this.createTransport();
transport.deliver(load);
}
}
class RoadLogistics extends Logistics {
createTransport() { return new Truck(); }
}
class SeaLogistics extends Logistics {
createTransport() { return new Ship(); }
}Pros
- Decouples client code from concrete classes — open/closed principle in action.
- Centralizes construction logic, so changes happen in one place.
- Makes it easy to swap implementations at runtime or per environment.
Cons
- Adds an extra layer of classes and indirection, which can feel heavy for small cases.
- Subclassing-based factories can lead to parallel class hierarchies that are hard to follow.
- If you only ever have one variant, this pattern is over-engineering.