When studying design patterns, there’s one point where you almost inevitably hit a wall.
That point is the Strategy and State patterns.
Place the UML (Unified Modeling Language) diagrams side by side and they look almost copy-pasted. There’s one interface, multiple implementations, and a context that holds them.
It’s fair to wonder, “Aren’t these just different names for the same thing?”
Let’s start with the conclusion. What separates the two patterns is intent, not structure. Strategy swaps algorithms from the outside; State lets the current state move itself to the next state internally.
Hold on to that one sentence as you read on, and you won’t confuse them again.
The implementation that removes real conditionals with state objects continues step by step in State Pattern Refactoring in Swift.
Why do their structures look so identical?
Both patterns are behavioral design patterns from the GoF (Gang of Four) design patterns book.
They use the same ingredients: a common interface, several implementing classes, and a context that holds them.
That’s why they’re genuinely hard to distinguish from the code alone.
Here’s what the Strategy pattern looks like in code.
protocol PaymentStrategy {
func pay(_ amount: Int)
}
struct CardPayment: PaymentStrategy {
func pay(_ amount: Int) { print("Payment of \(amount) won by card") }
}
struct KakaoPay: PaymentStrategy {
func pay(_ amount: Int) { print("Payment of \(amount) won with Kakao Pay") }
}
final class Checkout {
var strategy: PaymentStrategy
init(strategy: PaymentStrategy) { self.strategy = strategy }
func pay(_ amount: Int) { strategy.pay(amount) }
}
let checkout = Checkout(strategy: CardPayment())
checkout.pay(10000)
checkout.strategy = KakaoPay() // Swapped from the outside
checkout.pay(5000)
// Output:
// Payment of 10000 won by card
// Payment of 5000 won with Kakao Pay
The key point here is who swaps the strategy. It’s the external client code.
The developer—or someone outside—changed the payment method from card to Kakao Pay.
The strategy itself has no idea what comes next. It doesn’t care.
So what makes the State pattern different?
The State pattern lets the states themselves decide when to transition.
Think of a traffic light. The red light knows that green comes next, and the green light knows that yellow comes next.
In other words, each state contains the rule for moving to the next state.
protocol TrafficState {
func next(_ light: TrafficLight)
}
final class Red: TrafficState {
func next(_ light: TrafficLight) {
print("Red → green")
light.state = Green() // The state specifies the next state itself
}
}
final class Green: TrafficState {
func next(_ light: TrafficLight) {
print("Green → yellow")
light.state = Yellow()
}
}
final class Yellow: TrafficState {
func next(_ light: TrafficLight) {
print("Yellow → red")
light.state = Red()
}
}
final class TrafficLight {
var state: TrafficState = Red()
func change() { state.next(self) }
}
let light = TrafficLight()
light.change()
light.change()
light.change()
// Output:
// Red → green
// Green → yellow
// Yellow → red
Can you see the difference?
With Strategy, we swapped it directly from the outside, as in checkout.strategy = KakaoPay().
With State, light.state = Green() is handled by the state class itself. The client only calls change().
That is the key point.
Strategy is swapped from the outside; State transitions itself from the inside.
The decisive difference, summarized in three points
A verbal explanation can still be confusing, so let’s put it in a table.
| Category | Strategy pattern | State pattern |
|---|---|---|
| Intent | Replace the algorithm | Change behavior based on state |
| Who transitions | External client | The state object itself |
| Relationship between objects | They don’t know each other (independent) | They know and reference each other |
| Lifecycle | Usually remains once selected | Keeps changing during execution |
Pay particular attention to the second and third rows.
Strategies don’t know about one another. Card payment doesn’t need to know about Kakao Pay.
States, on the other hand, need to know one another. The red light directly creates and passes the green-light object.
Whether they “know each other or not” is the clearest clue for distinguishing the two patterns in code.
When should you use or avoid them?
Here’s the rule of thumb I use in practice.
| Situation | Choice |
|---|---|
| When there are multiple ways to do the same thing (sorting, payments, compression) | Strategy pattern |
| When an object behaves differently by situation and the situation changes | State pattern |
| When transition rules form a complex if-else block | Solve with the State pattern |
| When it’s simple enough to pass just one function | Both are overkill; use a closure |
There’s one more thing to keep in mind.
If there are only two or three states and transitions are simple, enum and switch are often enough without introducing a pattern.
Patterns are tools for managing complexity, not decorations that dress up simple code.
This is how it comes up in interviews
Q. The Strategy and State patterns have the same structure. How do you distinguish them?
Their structures are almost identical, but their intents differ. Strategy aims to replace an algorithm externally, while State aims to change behavior based on internal state. The decisive difference is who drives the transition: the client for Strategy, and the state object itself for State.
Q. In the State pattern, states reference one another. Isn’t that a problem?
That does create coupling between states. To reduce it, you can move transition logic out of the states and into the context or a separate transition table. When states multiply and transitions become tangled, using a state-machine library is another option.
Don’t be intimidated even if the diagrams look identical. Just ask “Who performs the transition?” and the answer becomes clear.
Swap it from the outside and it’s Strategy; let it transition itself from the inside and it’s State. If you remember that one sentence, this article has done its job. I’ll be back with another confusing pattern.

