Strategy
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
π StructureDashed line animations indicate the flow direction of data or requests
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.
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.
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.
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.
Commonly Compared Concepts
Template Method
A pattern that fixes the algorithm skeleton and delegates specific steps to subclasses
Strategy replaces the entire algorithm via composition, while Template Method redefines specific steps via inheritance. The unit and timing of replacement are the key differences.
Command
A behavioral pattern that encapsulates requests as objects for execution, undo, and queuing
Strategy encapsulates 'how to perform,' while Command encapsulates 'what to perform.' Strategy is about algorithm replacement; Command is about request objectification.
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.'