Design Patterns Factory Method
The Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Instead of writing new ConcreteClass() scattered throughout your code, you call a factory method that handles the creation decision for you.
The Real-World Analogy
A logistics company ships packages. When the package is in a city, it uses a van. When it goes overseas, it uses a cargo ship. The logistics manager does not build vehicles — they call a deliver() method, and the right transport type gets created automatically based on the destination. The Factory Method pattern works the same way.
Problem Without Factory Method
// Every time you need a different button style, you scatter "new" calls:
if (os == "Windows") {
button = new WindowsButton();
} else if (os == "Mac") {
button = new MacButton();
} else if (os == "Linux") {
button = new LinuxButton();
}
// Adding a new OS means hunting through all these if-else blocks. Messy!
Solution With Factory Method
// You call one method. The right object gets created behind the scenes. Button button = dialog.createButton(); // clean and consistent button.render();
UML Diagram
┌───────────────────────────┐
│ Dialog │ ← Creator (abstract)
├───────────────────────────┤
│ + createButton(): Button │ ← Factory Method (abstract)
│ + render() │
└─────────────┬─────────────┘
│
┌────────────┴────────────┐
│ │
┌─────────┴──────────┐ ┌──────────┴──────────┐
│ WindowsDialog │ │ WebDialog │ ← Concrete Creators
├────────────────────┤ ├─────────────────────┤
│ + createButton() │ │ + createButton() │
└─────────────────────┘ └────────────────────┘
│ │
▼ ▼
┌────────────────────┐ ┌──────────────────────┐
│ WindowsButton │ │ HTMLButton │ ← Concrete Products
│ + render() │ │ + render() │
│ + onClick() │ │ + onClick() │
└────────────────────┘ └──────────────────────┘
│ │
└───────────┬─────────────┘
│ implements
┌──────┴──────┐
│ Button │ ← Product Interface
│ + render() │
│ + onClick() │
└─────────────┘
How the Pattern Flows
Client code asks Dialog to render a form
│
▼
Dialog.render() calls this.createButton()
│
▼
Which Dialog am I?
/ \
WindowsDialog WebDialog
│ │
▼ ▼
new new
WindowsButton HTMLButton
│ │
└───────┬────────┘
▼
button.render() ← client only ever sees "Button", not the concrete type
Code Example (pseudocode)
// Product interface
interface Button {
render();
onClick(action);
}
// Concrete products
class WindowsButton implements Button {
render() { /* draws Windows-style button */ }
onClick(action) { /* Windows click handler */ }
}
class HTMLButton implements Button {
render() { /* draws HTML button */ }
onClick(action) { /* HTML click handler */ }
}
// Creator (abstract)
abstract class Dialog {
abstract Button createButton(); // ← factory method
render() {
Button btn = createButton(); // calls the subclass's factory method
btn.render();
}
}
// Concrete creators
class WindowsDialog extends Dialog {
Button createButton() {
return new WindowsButton(); // subclass decides which product
}
}
class WebDialog extends Dialog {
Button createButton() {
return new HTMLButton();
}
}
// Client
Dialog dialog;
if (config.OS == "Windows") {
dialog = new WindowsDialog();
} else {
dialog = new WebDialog();
}
dialog.render(); // client does not care which Button type was created
Step-by-Step Creation Flow
Step 1: Define the Product interface (Button)
↓
Step 2: Create Concrete Products (WindowsButton, HTMLButton)
↓
Step 3: Create an abstract Creator with the factory method
↓
Step 4: Create Concrete Creators that override the factory method
↓
Step 5: Client picks a Concrete Creator; calls the method; gets a Product
Factory Method vs Direct Instantiation
┌────────────────────────────┬──────────────────────────────┐ │ Direct Instantiation │ Factory Method │ ├────────────────────────────┼──────────────────────────────┤ │ new WindowsButton() │ dialog.createButton() │ │ Tight coupling │ Loose coupling │ │ Adding types = edit caller │ Adding types = new subclass │ │ Hard to test │ Easy to test (swap creator) │ └────────────────────────────┴──────────────────────────────┘
Real-World Uses
- UI frameworks — Create platform-specific buttons, text boxes, and menus through factory methods.
- Logging libraries — Produce different logger types (file, console, database) based on configuration.
- Payment processors — Generate the right payment handler (Stripe, PayPal, bank transfer) based on user choice.
- Document editors — Open the correct document type (PDF, DOCX, TXT) through one unified open() factory method.
When to Use Factory Method
- Use it when the exact type of object to create is unknown until runtime.
- Use it when you want subclasses to control what gets created.
- Use it when you want to centralise and isolate object creation logic.
Key Takeaways
- The Factory Method pattern moves the
newkeyword out of client code and into a dedicated method. - The creator class defines the factory method; subclasses override it to return a specific product.
- Client code works with the product through an interface, so it never depends on concrete classes.
- Adding a new product type means creating a new subclass — not editing existing code.
