Coffee, Code, and Patterns: Factory vs Strategy
When you first start reading about design patterns, some of them feel like they're just different names for the same idea.
Two of the biggest culprits:
- Factory Pattern
- Strategy Pattern
At first glance, both seem to deal with choosing something at runtime. But they're not the same. Let's break it down in a way that's actually memorable β with coffee β.
Factory Pattern: Ordering the Coffee
Imagine you walk into Starbucks. You say:
"I'll take a Latte, please."
Do you know how to steam the milk, grind the beans, or draw the little foam heart on top? Nope. That's not your problem. The barista (factory) takes your request and gives you the right coffee (object).
That's the Factory Pattern.
It hides the messy "creation logic" and just hands you the object you asked for.
Example in C#
// Product Interface
public interface ICoffee
{
void Serve();
}
public class Latte : ICoffee
{
public void Serve() => Console.WriteLine("Serving a Latte");
}
public class Cappuccino : ICoffee
{
public void Serve() => Console.WriteLine("Serving a Cappuccino");
}
// Factory
public class CoffeeFactory
{
public static ICoffee CreateCoffee(string type)
{
return type switch
{
"latte" => new Latte(),
"cappuccino" => new Cappuccino(),
_ => throw new ArgumentException("Unknown coffee type")
};
}
}
// Usage
var coffee = CoffeeFactory.CreateCoffee("latte");
coffee.Serve(); // Serving a Latte
Example in Python
class Coffee:
def serve(self):
raise NotImplementedError
class Latte(Coffee):
def serve(self):
print("Serving a Latte")
class Cappuccino(Coffee):
def serve(self):
print("Serving a Cappuccino")
class CoffeeFactory:
@staticmethod
def create_coffee(type: str) -> Coffee:
if type == "latte":
return Latte()
elif type == "cappuccino":
return Cappuccino()
else:
raise ValueError("Unknown coffee type")
coffee = CoffeeFactory.create_coffee("latte")
coffee.serve() # Serving a Latte
Takeaway:
Factory = Which coffee should I get?
Strategy Pattern: How You Drink It
Okay, now you've got your Latte. But here comes the next decision:
- Do you add sugar?
- Do you add honey?
- Do you bravely drink it black like a true developer who hasn't slept in 3 days?
This is the Strategy Pattern: the coffee object stays the same, but the behavior of sweetening changes. You can swap one strategy for another without rewriting your whole coffee machine.
Example in C#
public interface ISweetener
{
void AddSweetener();
}
public class Sugar : ISweetener
{
public void AddSweetener() => Console.WriteLine("Adding Sugar");
}
public class Honey : ISweetener
{
public void AddSweetener() => Console.WriteLine("Adding Honey");
}
public class CoffeeCup
{
private ISweetener _sweetener;
public CoffeeCup(ISweetener sweetener)
{
_sweetener = sweetener;
}
public void SetSweetener(ISweetener sweetener)
{
_sweetener = sweetener;
}
public void Drink()
{
Console.WriteLine("Coffee is ready...");
_sweetener.AddSweetener();
}
}
// Usage
var cup = new CoffeeCup(new Sugar());
cup.Drink(); // Coffee is ready... Adding Sugar
cup.SetSweetener(new Honey());
cup.Drink(); // Coffee is ready... Adding Honey
Example in Python
class Sweetener:
def add(self):
raise NotImplementedError
class Sugar(Sweetener):
def add(self):
print("Adding Sugar")
class Honey(Sweetener):
def add(self):
print("Adding Honey")
class CoffeeCup:
def __init__(self, sweetener: Sweetener):
self._sweetener = sweetener
def set_sweetener(self, sweetener: Sweetener):
self._sweetener = sweetener
def drink(self):
print("Coffee is ready...")
self._sweetener.add()
cup = CoffeeCup(Sugar())
cup.drink() # Coffee is ready... Adding Sugar
cup.set_sweetener(Honey())
cup.drink() # Coffee is ready... Adding Honey
Takeaway:
Strategy = How should I customize my coffee?
The Cheat Sheet (Factory vs Strategy)
Pattern | What it decides | Coffee analogy |
---|---|---|
Factory Pattern | Which object to create | Choosing Latte vs Cappuccino |
Strategy Pattern | Which behavior to execute | Choosing Sugar vs Honey |
Final Sip
- Use Factory when you need to create objects without hardcoding their classes.
- Use Strategy when you need to swap algorithms/behaviors without touching the main object.
So next time someone asks you about the difference, just say:
π Factory is about which coffee you order, Strategy is about how you drink it.
And if they still don't get itβ¦ well, maybe they need more coffee β.