Strategy

Intent

Strategy is a behavioral design pattern that let you define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.

Problem

One day you decided to create a navigation app for travelers. The app is centered around the beautiful-looking map, allowing users to orient quickly in any city. One of the most requested features of the app was automatic route planner, so you had planned to devote special attention to it. Users would enter the desired destination and the app would show the fastest route.

While the first version of the app was only able to build routes over roads, it suited the car travelers perfectly. But apparently, not everybody likes to drive on their vacation. So with the next update, you added an option to plan the walking routes. But after a little while, you had added one more option, which allowed users to build routes relying on public transportation.

But that was only beginning. In the nearest future you planned to add route builder for cyclists. And later on, another option for building routes along the sight seeings.

While from the business perspective the app was a success, the technical part caused you a lot of headaches.

Each time you added a new routing algorithm, the main Map class had grown twice its size. At some point, the beast became too hard to maintain.

Any change to search algorithms, such as fixing a bug or slightly tuning the algorithm's behavior, affected the whole class, increasing the chance of making an error in already working code.

Finally, the teamwork became inefficient. Your team mates, which you hired right after the successful release, complain that they spend too much time resolving merge conflicts in the code of new features since they all related to just one large class.

Solution

The Strategy pattern suggests to take a class that does something important in a lot of different ways and extract all these algorithms into separate classes called strategies.

The original class, called context, will receive a field for storing a reference to one of the strategies. The context will delegate the work to a linked strategy instead of executing it on its own.

The context won't be responsible for picking the appropriate algorithm for the job. Instead, the client will pass a desired strategy to the context.

In fact, the context won't know much about strategies at all. It will communicate with all strategies through a basic interface, which will only expose the method for triggering an algorithm. This will make the context independent from strategies, allowing you to add new algorithms or modify existing without changing the code of the context or other strategies.

In our navigation app, each routing algorithm will move to its own class with a single method buildRoute that accepts origin and destination and returns a collection of route checkpoints.

Even though each routing class might build a different route given the same arguments, the Map class won't really care which one is selected, since its primary job is to render a set of checkpoints on the map.

The Map will provide a method for switching active routing strategy, which will allow its clients, such as the buttons in the user interface, to alter current routing behavior.

Real-World Analogy

Transport

You have to get to the airport. You can catch a bus, order a cab, or get on your bicycle. The way of transportation is a strategy. You pick a strategy depending on the context, such as the budget or time constraints.

Strategy pattern example

Structure

Strategy pattern structure
  1. Context stores a reference to a Concrete Strategy object, but works with it through a common Strategy interface. Context should expose a setter that allows other objects to replace linked strategy object.

  2. Strategy defines a common interface for all strategies. This interface makes concrete strategies interchangeable in Context.

  3. Concrete Strategies implement different algorithms, which aim to accomplish the same task in various ways.

  4. The Context calls its strategy object each time when it needs to run that task. It doesn't know, however, in which way the task will be executed.

  5. Clients know what strategy should be picked depending on the situations. They can configure the Context with a different strategy at will in runtime using a setter.

Pseudocode

In this example, the Context uses strategies to execute various arithmetic operations.

// Common interface for all strategies.
interface Strategy is
    method algorithm(a, b)

// Each concrete strategy provides unique implementation.
class ConcreteStrategyAdd implements Strategy is
    method algorithm(a, b) is
        return a + b

class ConcreteStrategySubtract implements Strategy is
    method algorithm(a, b) is
        return a - b

class ConcreteStrategyMultiply implements Strategy is
    method algorithm(a, b) is
        return a * b

// Context (as a client) always works with strategies through a common
// interface. It does not know or care which strategy is currently active.
class Context is
    private strategy: Strategy

    method setStrategy(Strategy strategy) is
        this.strategy = strategy

    method executeStrategy(int a, int b) is
        return strategy.execute(a, b)


// The concrete strategy is picked on a higher level (for example, by
// application config) and passed to the client object. At any time, the
// strategy object can be replaced by a different strategy.
class ExampleApplication is
    method main() is
        Create context object.

        Read first number
        Read last number
        Read the desired action from user input

        if (action == addition) then
            context.setStrategy(new ConcreteStrategyAdd());

        if (action == subtraction) then
            context.setStrategy(new ConcreteStrategySubtract());

        if (action == multiplication) then
            context.setStrategy(new ConcreteStrategyMultiply());

        result = context.executeStrategy(First number, Second number);

Applicability

When you have an object that should be able to do the same task in lots of different ways.

The Strategy pattern allows you to alter the object's behavior at runtime by supplying it with different sub-objects that actually perform the work.

When you have lots of similar classes, that differ with in the way the execute some behavior.

The Strategy pattern allows you to combine all these classes into one by extracting all variants of the behavior into a separate class hierarchy, making the behavior of original class customizable.

When you don't want to expose algorithm's implementation details to other classes.

The Strategy pattern isolates code, internal data, and dependencies of algorithms from other objects by extracting them into their own classes.

An algorithm to be executed is selected by a monstrous conditional operator. Each branch of the conditional represents different algorithm.

Strategy lets you decompose the conditional by extracting each algorithm into their own classes, all of which implement a common interface. Context delegates execution to one of these objects, instead of implementing the behavior by itself.

How to Implement

  1. Identify an algorithm that the client would prefer to access through a "flex point."

  2. Define the common interface for all variations of the algorithm.

  3. One-by-one, extract all algorithms into their own classes. They all should follow the common Strategy interface.

  4. Add a field for storing a reference to the current strategy, as well as a setter to change it, into the Context class. The Context should work with this object only using the Strategy interface.

  5. Context's clients must provide it with a proper strategy objects when they need the Context to perform the work in a certain way.

Pros and Cons

  • Allows hot swapping algorithms at runtime.
  • Isolates the code and data of the algorithms from the other classes.
  • Replaces inheritance with delegation.
  • Follows the Open/Closed Principle.
  • Increases overall code complexity by creating multiple additional classes.
  • Client must be aware of the differences between strategies to pick a proper one.

Relations with Other Patterns

  • State, Strategy, Bridge (and to some degree Adapter) have similar solution structures. They all share elements of the "handle/body" idiom. They differ in intent - that is, they solve different problems.

  • Command and Strategy are very similar, since both used to parametrize context with some action. Command can be used to convert any operation into an object. Operation's parameters become fields of that object. The conversion allows deferred or remote execution, storing command history, etc.

    On ther other hand, the Strategy pattern usually describes different ways of doing the same thing. It helps to interchange these algorythms in a single context class.

  • Decorator lets you change the skin of an object. Strategy lets you change the guts.

  • Template Method uses inheritance to alter the algorithm by extending its parts in different classes. Strategy uses delegation to alter the object's behavior by replacing the nested strategy object. Template method works at the class level. Strategy allows you to change the behavior of individual objects.

  • State can be considered as an extension of the Strategy pattern. Both patterns use the composition to change the behavior of the main object by delegating the work to the helper objects. The Strategy pattern makes these objects completely independent. However, the State pattern allows state objects to alter the current state of the context with another state, making them interdependent.

Implementations in Different Programming Languages

Java