Factory Method Pattern
Define an interface for creating objects, but let subclasses decide which class to instantiate.
Overview
The Factory Method pattern is a creational design pattern that defines an interface for creating an object, but delegates the instantiation decision to subclasses. Instead of calling new directly, you call a factory method that returns an object of the expected type — the exact class being created is determined by the subclass.
This pattern is sometimes called a virtual constructor because it lets derived classes substitute the objects that a base class would otherwise create. The base class orchestrates the workflow; the subclass decides the materials.
Think of it like a staffing agency. A company (Creator) posts a job description (Product interface) and fills the role through the agency (factory method). Each regional agency (ConcreteCreator) may send a different type of specialist (ConcreteProduct), but the company treats all of them the same way because they all fulfill the role.
The Problem
Imagine you are building a logistics platform. Initially it handles only truck shipments, so your codebase is full of new Truck() calls. Six months later you need to add maritime freight. Every place that creates a Truck must change, and each change risks introducing bugs.
The real issue is tight coupling between the code that uses an object and the code that creates it. When creation logic is scattered throughout your application, adding a new variant means modifying many files — violating the Open/Closed Principle.
The Core Tension
Object creation is inherently concrete, but good software design favors programming to abstractions. The Factory Method pattern resolves this tension by isolating the concrete creation decision in one well-defined place: the subclass.
The Solution
Extract object creation into a dedicated method called the factory method. The base class (Creator) calls this method wherever it needs a product, but does not know which concrete product it will get. Subclasses override the factory method to produce the specific object they need.
The workflow becomes: the Creator's someOperation() calls this.factoryMethod(), uses the returned Product through its interface, and never knows (or cares) about the concrete type. Adding a new product type means adding a new Creator subclass — no existing code changes.
Class Diagram
Loading diagram...
Creator defines the factoryMethod() that returns a Product, and implements someOperation() in terms of that product. ConcreteCreatorA and ConcreteCreatorB each override factoryMethod() to instantiate their respective product. The Creator never imports or references a ConcreteProduct directly.
Implementation
The following example uses a UI dialog scenario. A Dialog base class renders a button by calling createButton(). WindowsDialog and WebDialog each override that method to produce the appropriate button type. The Button interface ensures both button types can be used interchangeably.
// Product interface
interface Button {
render(): void;
onClick(event: string): void;
}
// Concrete Products
class WindowsButton implements Button {
render(): void {
console.log("Render a button in Windows style");
}
onClick(event: string): void {
console.log(`Windows button handling click: ${event}`);
}
}
class HTMLButton implements Button {
render(): void {
console.log("Render a button in HTML style");
}
onClick(event: string): void {
console.log(`HTML button handling click: ${event}`);
}
}
// Creator (abstract)
abstract class Dialog {
// Factory method — subclasses decide what to create
abstract createButton(): Button;
// Uses the product without knowing its concrete type
renderWindow(): void {
const button = this.createButton();
button.render();
button.onClick("user clicked");
}
}
// Concrete Creators
class WindowsDialog extends Dialog {
createButton(): Button {
return new WindowsButton();
}
}
class WebDialog extends Dialog {
createButton(): Button {
return new HTMLButton();
}
}
// Client code
function renderUI(dialog: Dialog): void {
dialog.renderWindow();
}
const os = "web"; // could come from environment detection
const dialog: Dialog = os === "windows" ? new WindowsDialog() : new WebDialog();
renderUI(dialog);
// Output: Render a button in HTML style
// HTML button handling click: user clickedReal-World Use Cases
UI framework widgets. Cross-platform frameworks like Qt and Flutter use factory methods to produce platform-native controls. A WidgetFactory subclass for macOS creates MacButton, MacCheckbox, etc., while a Windows subclass creates their Windows equivalents. Application code talks only to the abstract Button interface and never needs platform conditionals scattered throughout.
Payment gateway integrations. An e-commerce backend may support Stripe, PayPal, and Braintree. A PaymentProcessorFactory subclass per provider creates the right client, handles provider-specific authentication, and wraps the response in a common PaymentResult. New providers are added as new subclasses — the checkout workflow never changes.
Database drivers and ORM connections. Frameworks like SQLAlchemy and Hibernate use factory methods to produce the right connection object depending on the configured database URL. The application calls engine.create_connection() and gets back a Connection object regardless of whether the backing store is PostgreSQL, MySQL, or SQLite.
Notification services. A notification system may dispatch via email, SMS, or push depending on user preferences. A NotifierFactory creates the right Notifier subclass. The sending loop always calls notifier.send(message) — it does not branch on channel type.
Trade-offs
Pros
- Open/Closed Principle. You can introduce new product types without modifying existing creator code — just add a new subclass pair.
- Single Responsibility. Product creation is isolated in the factory method, keeping the creator's primary logic clean.
- Loose coupling. The creator depends only on the Product interface, not on any concrete class, making it easy to swap implementations in tests or at runtime.
Cons
- Class proliferation. Every new product requires a new ConcreteProduct and usually a new ConcreteCreator. Small codebases can feel cluttered quickly.
- Inheritance-based flexibility. The pattern relies on subclassing, which is less composable than delegation-based alternatives. Changing the creator hierarchy later is expensive.
- Indirection overhead. For simple cases — where there is realistically only ever one product type — the pattern adds boilerplate with no benefit.
When to Use
- You do not know ahead of time which class your code should work with.
- You want to give users of your library or framework a way to extend its internal components.
- You need to reuse existing objects instead of rebuilding them each time (when combined with a pool or cache).
When to Avoid
- The product type is fixed and will never vary — a regular constructor is simpler and clearer.
- You only have one Creator and one Product — the pattern adds indirection without benefit.
- You need to create families of related objects — prefer Abstract Factory instead.
Related Patterns
Abstract Factory uses Factory Methods internally. Where Factory Method handles one product hierarchy, Abstract Factory coordinates creation across multiple related hierarchies (e.g., Button and Checkbox and TextField for each platform).
Template Method shares the same inheritance-based structure. The Creator's someOperation() is effectively a template method that calls the abstract factoryMethod() as a hook. If you understand one, the other follows naturally.
Prototype is an alternative approach to the same object-creation problem. Instead of delegating to a subclass factory method, Prototype clones an existing object. Prototype is more flexible when the class hierarchy is unstable or when configuration matters more than type.