Conceptly
← All Concepts
🎯

Strategy

BehavioralA behavioral pattern that encapsulates algorithms and makes them interchangeable at runtime

Strategy is a pattern that separates multiple algorithms serving the same purpose into individual classes and lets the consumer (Context) select and execute one. Because the code that uses the algorithm is separated from the algorithm itself, adding new algorithms or changing existing ones does not require modifying the calling side.

β–ΆArchitecture Diagram

πŸ” Structure

Dashed line animations indicate the flow direction of data or requests

Why do you need it?

When a single feature needs different logic depending on conditions, the most natural first attempt is if-else or switch. Three payment methods produce three branches; five validation rules produce five branches. With every new option, another branch is added to the same method, and as existing and new branches subtly overlap, the test surface grows with them. When fixing one branch breaks another, the problem is not the logic's complexity but the structure that packs all the logic into one place.

Why did this approach emerge?

When GoF formalized Strategy in 1994, the problem was already old. Procedural programming used function pointers to swap algorithms; object-oriented languages used inheritance. But inheritance is fixed at compile time, so it could not provide the flexibility of changing algorithms at runtime. Strategy is the canonical application of the 'composition over inheritance' design principle. Modern languages with higher-order functions, closures, and functional interfaces make Strategy lighter to implement, but the core idea of 'separating algorithms into replaceable units' has not changed.

How does it work inside?

Strategy has three roles. The Strategy interface defines a common method such as execute(). Concrete Strategy classes implement this interface, each containing a different algorithm. The Context holds a field of the Strategy interface type and calls that field's method when execution is needed. The key property is that the Context does not know the concrete Strategy. Because it depends only on the interface, it calls execution the same way regardless of which algorithm is provided. To change the strategy, you inject a different Strategy object into the Context. Conditionals vanish, replaced by object composition that determines behavior. A caveat: strategies must be completely independent of each other. If Strategy A's result influences Strategy B's input, the Strategy pattern may not be appropriate.

What is it often confused with?

Strategy and State are nearly identical in structure. Both have a Context delegating execution to an interface, with swappable concrete classes. The difference is intent. In Strategy, the client explicitly selects an algorithm for its purpose; in State, behavior changes automatically based on the object's internal state. With Strategy, the client knows which strategy is in use; with State, state transitions happen internally and the client may be unaware. Template Method is also compared. Both deal with algorithm variation, but Template Method uses inheritance where the parent class holds the skeleton and subclasses fill in specific steps, while Strategy uses composition to delegate the entire algorithm to an external object. If you need runtime swapping, Strategy fits; if you want to fix the algorithm skeleton and vary only specific steps, Template Method fits.

When should you use it?

The question Strategy answers is 'Are there 2+ ways to perform the same task, and is that count likely to grow?' When the answer is yes, it is time to consider Strategy. Separating each payment method's processing logic into a Strategy in a payment system means new payment methods can be added without touching the existing flow. It is also appropriate when behavior must change at runtime based on configuration or user selection. When exporting files, making CSV, JSON, and XML each a Strategy lets the Context call 'export' regardless of format. Conversely, if there is only one algorithm with little chance of change, Strategy is unnecessary abstraction. Introducing Strategy for two branches only adds classes and makes code harder to read. The decision point is less 'how many branches exist now' and more 'is this branching an axis that will grow independently.'

Sorting method swap -- selecting a sorting algorithm based on data size or characteristicsPayment processing -- separating logic for card, bank transfer, and points paymentsValidation rules -- applying different validation strategies per input fieldCompression/serialization -- choosing the encoding method at runtime based on the situation