Strategy Pattern: Swappable Behaviour
How the strategy pattern replaces if-else chains with interchangeable behaviours behind one interface. Three Java discount strategies turn a price of 120 into 120.00, 108.00 and 105.00.
The strategy pattern puts each variation of an algorithm behind a common interface so the calling code, the context, can choose or swap it at runtime without conditional logic. In Java a one-method functional interface plus lambdas is enough. Interviewers expect the contrast: in Strategy the client picks the behaviour from outside, while in State the object switches it itself.
The strategy pattern puts each variation of an algorithm behind a common interface so the caller can choose or swap it at runtime. In Java, a one-method interface plus lambdas is enough: three discount strategies on a price of 120 gave 120.00, 108.00 and 105.00 with no conditional logic in the caller.
- The strategy pattern has three parts: a strategy interface declaring the operation, concrete strategies implementing it, and a context that receives a strategy and calls it.
- Three Java discount strategies written as lambdas turned a price of 120 into 120.00, 108.00 and 105.00, with no conditional logic in the calling loop.
- Java's Comparator is a standard-library example of the strategy pattern: list.sort(Comparator.comparing(...)) passes an ordering strategy in.
- In the strategy pattern the client chooses the algorithm from outside, while in the state pattern the object switches its own behaviour as its state changes.
- Strategy uses composition, while Template Method uses inheritance, with a base class fixing the algorithm skeleton and subclasses filling in steps.
01The problem
Consider a checkout that applies discounts. At first there is one rule. Then a percentage discount, a flat amount, a loyalty rule, a seasonal rule. A single method turns into a long chain of conditions on a type flag, every new rule edits that method, and every edit risks breaking old rules. Testing one rule means setting up the whole method.
The strategy pattern separates what varies. Each variation becomes its own small unit of behaviour behind an interface, and the code that uses it just calls the interface.
02The structure
Three parts. The strategy interface declares the operation (apply(price)). Concrete strategies implement it in different ways. The context is the code that uses a strategy, receives it from outside, and calls it without caring which one it is.
Because the context holds a reference to the interface, you can change the strategy at runtime, pass different strategies in different situations, and add new ones without editing the context. It is also easy to test: each strategy is a small isolated piece.
03Java: lambdas make it light
interface Discount { double apply(double price); }
Map<String, Discount> strat = new LinkedHashMap<>();
strat.put("none", p -> p);
strat.put("10% off", p -> p * 0.9);
strat.put("flat 15", p -> Math.max(0, p - 15));
for (var e : strat.entrySet())
System.out.printf("%s: %.2f%n", e.getKey(), e.getValue().apply(120));The output was none: 120.00, 10% off: 108.00 and flat 15: 105.00. The loop does not know which discount it is applying. Because Discount has one abstract method it is a functional interface, so lambdas fit directly and no separate class files are needed for simple rules. The standard library works the same way: Comparator is a strategy for ordering, and list.sort(Comparator.comparing(...)) passes one in. Use named classes when a strategy has its own state or enough logic to deserve a name and tests.
04Choosing a strategy at runtime
Often the choice depends on data: the customer's tier, a feature flag, a config value. Keep that selection in one spot (a factory, a map lookup, or a configuration) and have the rest of the code receive the chosen strategy. For example, Discount d = strategies.getOrDefault(user.tier(), strategies.get("none")). The map replaces a chain of if statements, and a missing key has an explicit default.
If strategies need data to decide whether they apply, give the interface a second method such as boolean applies(Order o), then pick the first strategy that applies. This is the start of a rules engine.
05Strategy versus similar patterns
State pattern looks alike structurally, but the object changes its own strategy as its state changes (a document moving from draft to published), while with Strategy the client picks it from outside. Template Method uses inheritance: a base class fixes the algorithm skeleton and subclasses fill in steps. Strategy uses composition, which is usually more flexible because the behaviour can be swapped without making new subclasses of the context.
In languages where functions are values, you often do not need the pattern's ceremony: pass a function. The idea remains the same. The interface-based version helps when strategies carry configuration, need several methods, or should be discoverable by name.
06Common mistakes
Do not create strategy classes for behaviour that will never vary. Two outcomes do not need an interface. Keep the interface narrow: if every strategy has to receive the whole context object, they are coupled to it. Avoid strategies that depend on each other's internal state. And do not let the context check which concrete type it holds; if it does (if (s instanceof X)), the abstraction has failed and a method belongs on the interface.
07Common interview questions
Q: What is the strategy pattern?
A: It defines a family of interchangeable algorithms behind an interface so they can be selected and swapped at runtime.
Q: What problem does it solve?
A: Long conditionals choosing behaviour, and the need to add new behaviours without editing existing code.
Q: Example in the Java standard library?
A: Comparator passed to sort, or ThreadPoolExecutor's rejection policy.
Q: Strategy versus State?
A: In Strategy the client chooses the algorithm. In State the object switches behaviour itself as its state changes.
Q: Strategy versus Template Method?
A: Strategy composes behaviour passed in from outside. Template Method inherits a fixed skeleton and overrides steps.
Q: Which principle does it support?
A: Open/closed, and favouring composition over inheritance.