The State pattern and the Strategy pattern have nearly identical class diagrams. What actually distinguishes them, and how would you tell which one a given piece of code is using?
answer
- identical diagram, different intent
- client picks Strategy; object enters State
- strategies ignore each other; states know successors
- Strategy = how; State = what's legal now
- state is persisted and user-visible
basics
~20 sSame shape, different purpose. With Strategy the caller chooses one interchangeable algorithm and it normally stays put. With State the object swaps its own behavior as its lifecycle advances, and the states know which state comes next.
solid answer
~50 sStructurally both are: an interface, several implementations, and a context that delegates to a held reference. The differences are about intent and dynamics. **Who chooses?** Strategy is injected by the client ("sort with quicksort"); a State is entered by the object itself as events arrive. **How often does it change?** A Strategy is usually set once and rarely swapped; a State changes constantly — that *is* the point. **Do implementations know each other?** Strategies are mutually ignorant and interchangeable; states typically know their successors, or a transition table does, and swapping any two states arbitrarily would be nonsense. **What varies?** Strategy varies *how* one task is done, with the same observable outcome; State varies *what is legal and what happens*, including rejecting operations. **Is the choice observable?** Strategy is an implementation detail; the current state is domain-meaningful and often persisted and shown to users. Tell them apart by asking whether the implementations form a graph with a lifecycle, or an unordered menu.
go deeper
Say the diagrams match but the intent differs: the caller picks a Strategy, while an object moves through States on its own as its lifecycle advances.
Give concrete discriminators — who selects, how often it changes, whether implementations know each other — plus a domain example of each.
Add substitutability (Liskov) reasoning, persistence and audit implications, illegal-transition handling, and the State-holding-a-Strategy hybrid.
Frame State as an implementation of a finite state machine with an explicit transition relation and invariants, contrast with Bridge and Command, and explain how mislabeling a lifecycle as pluggable behavior removes the guardrails that keep aggregates consistent.
## Why the confusion exists Draw both patterns and you get the same picture: ``` Context ──has-a──> «interface» Behavior ▲ ┌────────────┼────────────┐ ImplA ImplB ImplC ``` GoF explicitly groups them as behavioral patterns built on the same mechanism — **replace conditional logic with polymorphic delegation**. UML cannot express intent, so the diagram is genuinely identical. The distinction is entirely in *dynamics and meaning*, and interviewers ask it precisely because it forces you past diagram-memorization. ## The six discriminators | Question | **Strategy** | **State** | |---|---|---| | Who selects the implementation? | The **client** injects it (constructor arg, setter, config, DI container). | The **object itself**, driven by events; the client only sends events. | | How often does it change? | Rarely, often never after construction. | Continuously — the change *is* the feature. | | Do implementations know each other? | No. Mutually ignorant, freely interchangeable. | Usually yes (or a table knows) — they form a **directed graph** of legal successors. | | What varies? | *How* a task is accomplished; the contract's outcome is the same. | *Whether and what* an operation does — including outright rejection. | | Is the current choice domain-visible? | Usually an implementation detail. | Domain-meaningful: shown to users, persisted, audited, reported on. | | Typical vocabulary | Compression algorithm, pricing rule, routing policy, sort order. | Draft/Published, Open/Closed, Idle/Running/Failed, Pending/Paid/Shipped. | ## Worked contrast **Strategy.** A `Checkout` object takes a `TaxCalculator`. `EuVatCalculator` and `UsSalesTaxCalculator` never mention each other; there is no notion of "moving from EU tax to US tax". Which one you get is decided outside, from configuration or the customer's country. Every strategy answers the same question — "how much tax?" — and all answers are valid outputs of the same operation. **State.** A `Subscription` is `Trialing`, `Active`, `PastDue`, or `Cancelled`. `Trialing.charge()` moves it to `Active`; `Cancelled.charge()` refuses. No client injects `Cancelled` — the object arrives there by processing a cancel event. And it matters that `PastDue → Active` is legal while `Cancelled → Trialing` is not: the implementations are ordered by a lifecycle. ## The classic hybrid — and why it is not a contradiction A common design has states *own* strategies: `PastDue` uses an `AggressiveDunningStrategy`, `Active` uses a `QuietRetryStrategy`. Nothing is wrong here; the axes are orthogonal. The lifecycle position is State; the pluggable how-to inside a position is Strategy. Equally, a Strategy can be **swapped at runtime** (adaptive algorithms picking a different sort by input size) without becoming State — because the choice is not a domain lifecycle, is not persisted, and the implementations do not form a legality graph. ## Reading unfamiliar code Ask, in order: 1. **Does any implementation assign the context's reference to another implementation?** If yes → State. Strategies never elect their successor. 2. **Is the current implementation identity persisted or displayed?** Persisted discriminator column, an enum in an API response, a badge in the UI → State. 3. **Could you shuffle the implementations arbitrarily and still have sensible behavior?** If yes → Strategy. If "you cannot go from Shipped back to New" is meaningful → State. 4. **Do some implementations reject calls that others accept?** Systematic rejection is a State smell; a Strategy that throws for the same input another strategy handles usually violates the Liskov Substitution Principle (substituting any implementation should not break the caller's expectations). ## Neighbors worth naming - **Bridge** shares the shape too, but its axis is *abstraction vs. implementation* varying independently (a `Shape` hierarchy over a `Renderer` hierarchy), typically fixed at construction. - **Command** encapsulates an *invocation* rather than a *mode* or an *algorithm*; events driving a state machine are frequently Commands. - **Finite State Machine** is the formal model behind State; Strategy has no equivalent formalism because there is no transition relation to formalize. ## Why the distinction pays off Naming it correctly changes what you build around it. Call it State and you naturally ask: what is the transition table, which transitions are illegal, what happens on entry/exit, how is it persisted, is the transition audited, is replaying an event idempotent. Call it Strategy and you ask: is the interface truly substitutable, can it be selected from configuration, is it testable in isolation. Mislabeling a lifecycle as "pluggable behavior" is how systems end up with an `Order` that can be shipped after being refunded.
- Can a Strategy be changed at runtime without it becoming State?Yes. An adaptive sorter picking insertion sort for small inputs and quicksort for large ones swaps strategies constantly and is still Strategy: the choice is not a domain lifecycle, the implementations do not form a legality graph, nothing is persisted, and no implementation elects its successor.
- Can State and Strategy appear together in one design?Routinely. The lifecycle position is State; a pluggable algorithm used *within* a position is Strategy — for example a PastDue subscription state holding an aggressive dunning strategy while Active holds a quiet retry strategy. The axes are orthogonal.
- You inherit a class with an interface and three implementations. What single question best classifies it?Does any implementation set the context's reference to a different implementation? Only states elect their successors. Secondary tells: the current choice is persisted or shown to users, and some implementations reject calls others accept.
Strategy is choosing a route app — fastest, shortest, avoid tolls. All get you there; you pick, and the options do not know each other. State is the gear your car is in: Reverse, Drive, Park. The same pedal does different things, you cannot jump from Drive to Reverse at speed, and the gear is displayed on the dashboard because it is part of what the car currently is.
saying these in an interview costs you the question
- 'They are the same pattern' — they share a mechanism, not an intent; the difference drives transition tables, persistence, and auditing.
- 'State is Strategy where the strategy changes' — adaptive strategies also change; the real markers are lifecycle ordering, self-election of successors, and domain visibility.
- 'You can always tell from the UML' — you cannot; nothing about intent is expressible in the class diagram.
- Designing states as freely interchangeable, which discards exactly the illegal-transition protection State exists to provide.
- Writing strategies that throw for inputs other strategies handle — that breaks substitutability and usually means you actually had states.