Software Design

Strategy vs State: Same structure, so what’s the difference?

The Strategy pattern selects an algorithm externally, while the State pattern lets the current state drive internal transitions. These two behavioral patterns share a class structure but differ in intent and in who controls change.

4 min read
Cover image for Strategy vs State: Same structure, so what’s the difference?

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.

A flow where each state moves itself to the next—that’s what State is all about
A flow where each state moves itself to the next—that’s what State is all about
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 you place the two code samples side by side, “who changes it” becomes clear
When you place the two code samples side by side, “who changes it” becomes clear

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.