Skip to main content

Command Palette

Search for a command to run...

Week 2: The Factory Method Pattern Explained Simply

Design Patterns Demystified Series

Updated
4 min read
Week 2: The Factory Method Pattern Explained Simply

In Week 1, we explored the Singleton Pattern — ensuring a single instance of a class exists globally.

This week, we’re diving into a slightly more sophisticated creational pattern:

The Factory Method Pattern, one of the official Gang of Four (GoF) design patterns.

Let’s break it down the simple way — with plain language, real-world analogies, and working code.


🤖 What is the Factory Method Pattern?

The Factory Method Pattern is a creational design pattern that:

  • Defines an interface for creating an object,

  • But let subclasses decide which class to instantiate.

Instead of hardcoding object creation (new), the pattern delegates the instantiation to a factory method, typically declared in a superclass and overridden in subclasses.

This promotes loose coupling and follows the Open/Closed Principle — your code is open for extension but closed for modification.


☕ Real-World Analogy: The Coffee Machine

Imagine an office cafe where employees can order coffee. But instead of preparing the drink themselves, they select a coffee flavor, and the machine takes care of everything.

Here's what happens:

  • Alice orders Espresso

  • Bob orders Cappuccino

Behind the scenes, the machine selects the correct recipe and serves the drink. Each type of coffee has a different preparation method, but the interface to the user remains the same.

In this analogy:

  • The coffee machine is the abstract class (with a factory method)

  • Each flavor is a concrete subclass that defines how to create its specific coffee

  • The user (client) only needs to request a flavor; they don’t know (or care) how it’s made

Both Alice and Bob interact with the same machine, using the same button interface, but get different results based on their input.


☕ Let's Translate That Into Code

  1. Product Interface – Coffee.java

     public interface Coffee {
         void brewCoffee(String user);
     }
    
  2. Concrete Products – EspressoCoffee.java and CappuccinoCoffee.java

     public class EspressoCoffee implements Coffee {
         @Override
         public void brewCoffee(String user) {
             System.out.println("Brewing Espresso coffee for " + user);
         }
     }
    
     public class CappuccinoCoffee implements Coffee {
         @Override
         public void brewCoffee(String user) {
             System.out.println("Brewing Cappuccino coffee for " + user);
         }
     }
    
  3. Creator Abstract Class – CoffeeSelection.java

     public abstract class CoffeeSelection {
         public void serveCoffee(String user) {
             Coffee coffee = createCoffee(); // Factory Method
             coffee.brewCoffee(user);
         }
    
         protected abstract Coffee createCoffee();
     }
    
  4. Concrete Creators – EspressoFlavour.java and CappuccinoFlavour.java

public class EspressoFlavour extends CoffeeSelection {
    @Override
    protected Coffee createCoffee() {
        return new EspressoCoffee();
    }
}
public class CappuccinoFlavour extends CoffeeSelection {
    @Override
    protected Coffee createCoffee() {
        return new CappuccinoCoffee();
    }
}
  1. Factory Dispatcher – CoffeeMachineFactory.java

     public class CoffeeMachineFactory {
         public static CoffeeSelection getMyCoffee(String type) throws Exception {
             if (type.equalsIgnoreCase("espresso")) {
                 return new EspressoFlavour();
             } else if (type.equalsIgnoreCase("cappuccino")) {
                 return new CappuccinoFlavour();
             } else {
                 throw new Exception("Selected Coffee flavour not available");
             }
         }
     }
    
  2. Client Code – CoffeeShop.java

     public class CoffeeShop {
         public static void main(String[] args) throws Exception {
             CoffeeSelection espresso = CoffeeMachineFactory.getMyCoffee("espresso");
             espresso.serveCoffee("Alice");
    
             CoffeeSelection cappuccino = CoffeeMachineFactory.getMyCoffee("cappuccino");
             cappuccino.serveCoffee("Bob");
         }
     }
    

    ✅ Output:

     Brewing Espresso coffee for Alice
     Brewing Cappuccino coffee for Bob
    

🎯 What This Demonstrates

  • CoffeeSelection defines the factory method: createCoffee()

  • Subclasses like EspressoFlavour and CappuccinoFlavour override the factory method to provide specific product implementations

  • Client code (CoffeeShop) interacts only with the abstract interface and doesn't worry about the creation logic

  • This allows us to add new coffee types in the future without changing existing code — a great example of the Open/Closed Principle (i.e, one of the five SOLID principles of object-oriented design- Open for extension but closed for modification)


🧠 Why Use the Factory Method Pattern?

👍 Advantages:

  • Encapsulates object creation logic

  • Promotes code reusability and clean architecture

  • Encourages polymorphism — client code uses the abstract type

  • Easy to extend — just add a new subclass and override the factory method


📌 When to Use It:

  • When you want to delegate the responsibility of instantiating objects to child classes

  • When the creation process might change depending on context or input

  • When working with frameworks or libraries that expect you to plug in behavior via subclassing


Want to see how this same example evolves into the Abstract Factory Pattern (for regional coffee experiences)? Stay tuned for Week 3!


🔜 Next up: The Abstract Factory Pattern!

“Next up: the Abstract Factory Pattern! We're continuing our journey through design patterns with clear, beginner-friendly explanations and practical examples.”

This pattern takes flexible object creation to the next level — it lets you create families of related objects without specifying their concrete classes. Whether you're building cross-platform UIs or themed product bundles, Abstract Factory helps ensure consistency and scalability across components.

Follow along each week as we demystify these patterns and help you build cleaner, modular, and maintainable code — one pattern at a time.

✅ Call to Action (CTA)

🚀 Want to level up your design pattern skills?
Subscribe or follow the series — we’ll walk through each pattern with examples, analogies, and real-world code you can use today.


Note: AI-generated Image

Design Patterns

Part 3 of 25

Let’s be honest—most devs would rather code than study design patterns. They seem academic and full of jargon. But this guide is different: plain language, real-life analogies, and practical examples that make your code smarter, cleaner, and scalable

Up next

Week 3: The Abstract Factory Pattern Explained Simply

Design Patterns Demystified Series