Simplifying Design Patterns : Factory Method
Introduction Design patterns are proven solutions to common software design problems. In this article, we’ll simplify the Factory Method pattern—explaining how it works, when to use it, and how to implement it with clear examples. The examples are inspired by Refactoring Guru and Dive Into Design Patterns (Alexander Shvets), distilled to their essence. Let’s dive in! How Does the Factory Method Work? The Factory Method is a creational design pattern that provides an interface for creating objects in a superclass while allowing subclasses to alter the type of objects created. Example Scenario: A Restaurant Kitchen Imagine a restaurant where: The Kitchen class defines how dishes are made. Each dish (e.g., Pizza, Burger, Pasta) follows a common Dish interface with methods like prepare(). Instead of hardcoding dish creation, the Kitchen delegates instantiation to subclasses (PizzaStation, BurgerStation). This way, adding a new dish (e.g., Taco) doesn’t require modifying the Kitchen—just creating a new subclass. When to Use the Factory Method? Use this pattern when: You don’t know object types beforehand – The exact class of objects (e.g., dishes) isn’t known until runtime. You want extensibility – Users of your library/framework should be able to add new types (e.g., new dishes) without changing existing code. You need object reuse – Avoid rebuilding objects by caching and reusing them (e.g., reusing a preconfigured Pizza object). How to Implement the Factory Method Step-by-Step (Restaurant Example) Define a Common Interface All dishes implement a Dish interface with shared methods (e.g., prepare(), cook()). Create the Base Factory (Kitchen) The Kitchen class declares an abstract (or default) factory method: public abstract Dish createDish(String type); Implement Factory Subclasses Subclasses (PizzaStation, BurgerStation) override createDish() to instantiate specific dishes: public class PizzaStation extends Kitchen { @Override public Dish createDish() { return new Pizza(); // Pizza implements Dish } } Optional: Use Parameters for Variants If a dish has variations (e.g., PastaType), pass a parameter to the factory method instead of creating more subclasses: public Dish createDish(String pastaType) { return new Pasta(pastaType); } Make the Factory Method Abstract (If Needed) If the base factory method has no default logic, declare it abstract to force subclasses to implement it. Why Avoid Hardcoding? A bad alternative would be hardcoding every dish in the Kitchen: // ❌ Hardcoded (inflexible) public class Kitchen { public Pizza makePizza() { ... } public Burger makeBurger() { ... } // Requires changes for every new dish! } Problems: Violates the Open/Closed Principle (code isn’t open for extension). Becomes bloated as new dishes are added. Diagram The Kitchen (creator) delegates dish creation to subclasses. All dishes implement the Dish interface. Key Takeaways ✅ Decouples code – The Kitchen doesn’t depend on concrete dishes. ✅ Supports scalability – Add new dishes without modifying existing classes. ✅ Promotes reuse – Share or cache objects (e.g., a preconfigured Pizza). Use the Factory Method when you need flexible object creation without tight coupling!

Introduction
Design patterns are proven solutions to common software design problems. In this article, we’ll simplify the Factory Method pattern—explaining how it works, when to use it, and how to implement it with clear examples. The examples are inspired by Refactoring Guru and Dive Into Design Patterns (Alexander Shvets), distilled to their essence. Let’s dive in!
How Does the Factory Method Work?
The Factory Method is a creational design pattern that provides an interface for creating objects in a superclass while allowing subclasses to alter the type of objects created.
Example Scenario: A Restaurant Kitchen
Imagine a restaurant where:
- The
Kitchen
class defines how dishes are made. - Each dish (e.g.,
Pizza
,Burger
,Pasta
) follows a commonDish
interface with methods likeprepare()
. - Instead of hardcoding dish creation, the
Kitchen
delegates instantiation to subclasses (PizzaStation
,BurgerStation
).
This way, adding a new dish (e.g., Taco
) doesn’t require modifying the Kitchen
—just creating a new subclass.
When to Use the Factory Method?
Use this pattern when:
- You don’t know object types beforehand – The exact class of objects (e.g., dishes) isn’t known until runtime.
- You want extensibility – Users of your library/framework should be able to add new types (e.g., new dishes) without changing existing code.
-
You need object reuse – Avoid rebuilding objects by caching and reusing them (e.g., reusing a preconfigured
Pizza
object).
How to Implement the Factory Method
Step-by-Step (Restaurant Example)
-
Define a Common Interface
- All dishes implement a
Dish
interface with shared methods (e.g.,prepare()
,cook()
).
- All dishes implement a
-
Create the Base Factory (Kitchen)
- The
Kitchen
class declares an abstract (or default) factory method:
public abstract Dish createDish(String type);
- The
-
Implement Factory Subclasses
- Subclasses (
PizzaStation
,BurgerStation
) overridecreateDish()
to instantiate specific dishes:
public class PizzaStation extends Kitchen { @Override public Dish createDish() { return new Pizza(); // Pizza implements Dish } }
- Subclasses (
-
Optional: Use Parameters for Variants
- If a dish has variations (e.g.,
PastaType
), pass a parameter to the factory method instead of creating more subclasses:
public Dish createDish(String pastaType) { return new Pasta(pastaType); }
- If a dish has variations (e.g.,
-
Make the Factory Method Abstract (If Needed)
- If the base factory method has no default logic, declare it
abstract
to force subclasses to implement it.
- If the base factory method has no default logic, declare it
Why Avoid Hardcoding?
A bad alternative would be hardcoding every dish in the Kitchen
:
// ❌ Hardcoded (inflexible)
public class Kitchen {
public Pizza makePizza() { ... }
public Burger makeBurger() { ... }
// Requires changes for every new dish!
}
Problems:
- Violates the Open/Closed Principle (code isn’t open for extension).
- Becomes bloated as new dishes are added.
Diagram
The Kitchen
(creator) delegates dish creation to subclasses. All dishes implement the Dish
interface.
Key Takeaways
✅ Decouples code – The Kitchen
doesn’t depend on concrete dishes.
✅ Supports scalability – Add new dishes without modifying existing classes.
✅ Promotes reuse – Share or cache objects (e.g., a preconfigured Pizza
).
Use the Factory Method when you need flexible object creation without tight coupling!