How does the Strategy Pattern work?

Design PatternsStrategy Pattern

Design Patterns Problem Overview


How does it work, what is it used for and when should one use it?

Design Patterns Solutions


Solution 1 - Design Patterns

Let's explain the strategy pattern the easy way:

You have a class Car() with a method run(), so you use it this way in a pseudo language:

mycar = new Car()
mycar.run()

Now, you may want to change the run() behavior on the fly, while the program is executing. For example, you might want to simulate a motor failure or the use of a "boost" button in a video game.

There are several ways to do this simulation: using conditional statements and a flag variable is one way. The strategy pattern is another: it delegates the behavior of the run() method to another class:

Class Car()
{
    this.motor = new Motor(this) 

    // passing "this" is important for the motor so it knows what it is running

    method run()
    {
        this.motor.run()
    }

    method changeMotor(motor)
    {
        this.motor = motor 
    }

}

If you want to change the car's behavior, you can just change the motor. (Easier in a program than in real life, right? ;-) )

It's very useful if you have a lot of complex states: you can change and maintain them much more easily.

Solution 2 - Design Patterns

Problem

The strategy pattern is used to solve problems that might (or is foreseen they might) be implemented or solved by different strategies and that possess a clearly defined interface for such cases. Each strategy is perfectly valid on its own with some of the strategies being preferable in certain situations that allow the application to switch between them during runtime.

Code Example

namespace StrategyPatterns
{
  // Interface definition for a Sort algorithm
  public interface ISort
  {
    void Sort(List<string> list)
  }

  // QuickSort implementation
  public class CQuickSorter : ISort
  {
    void Sort(List<string> list)
    {
      // Here will be the actual implementation
    }
  }

  // BubbleSort implementation
  public class CBubbleSort : ISort
  {
    void Sort(List<string> list)
    {
      // The actual implementation of the sort
    }
  }

  // MergeSort implementation
  public class CMergeSort : ISort
  {
    void Sort(List<string> list)
    {
      // Again the real implementation comes here
    }
  }

  public class Context
  {
    private ISort sorter;

    public Context(ISort sorter)
    {
      // We pass to the context the strategy to use
      this.sorter = sorter;
    }

    public ISort Sorter
    {
      get{return sorter;)
    }
  }

  public class MainClass
  {
    static void Main()
    {
       List<string> myList = new List<string>();

       myList.Add("Hello world");
       myList.Add("Another item");
       myList.Add("Item item");

       Context cn = new Context(new CQuickSorter());
       // Sort using the QuickSort strategy
       cn.Sorter.Sort(myList);
       myList.Add("This one goes for the mergesort");
       cn = new Context(new CMergeSort());
       // Sort using the merge sort strategy
       cn.Sorter.Sort(myList);
    }
  }
}

Solution 3 - Design Patterns

  • What is a Strategy? A strategy is a plan of action designed to achieve a specific goal;
  • “Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.” (Gang of Four);
  • Specifies a set of classes, each representing a potential behaviour. Switching between those classes changes the application behaviour. (the Strategy);
  • This behaviour can be selected at runtime (using polymorphism) or design time;
  • Capture the abstraction in an interface, bury implementation details in derived classes;

enter image description here

  • An alternative to the Strategy is to change the application behaviour by using conditional logic. (BAD);

  • Using this pattern makes it easier to add or remove specific behaviour, without having to recode and retest, all or parts of the application;

  • Good uses:

  • When we have a set of similar algorithms and its need to switch between them in different parts of the application. With Strategy Pattern is possible to avoid ifs and ease maintenance;

  • When we want to add new methods to superclass that don’t necessarily make sense to every subclass. Instead of using an interface in a traditional way, adding the new method, we use an instance variable that is a subclass of the new Functionality interface. This is known as Composition : Instead of inheriting an ability through inheritance the class is composed with Objects with the right ability;

Solution 4 - Design Patterns

A closely related pattern is the Delegate pattern; in both cases, some of the work is passed to some other component. If I understand correctly, the difference between these patterns is this (and please correct me if I'm wrong):

  • In the Delegate pattern, the delegate is instantiated by the enclosing (delegating) class; this allows for code reuse by composition rather than inheritance. The enclosing class may be aware of the delegate's concrete type, e.g. if it invokes its constructor itself (as opposed to using a factory).

  • In the Strategy pattern, the component that executes the strategy is a dependency provided to the enclosing (using) component via its constructor or a setter (according to your religion). The using component is totally unaware of what strategy is in use; the strategy is always invoked via an interface.

Anyone know any other differences?

Solution 5 - Design Patterns

Directly from the Strategy Pattern Wikipedia article:

> The strategy pattern is useful for situations where it is necessary to dynamically swap the algorithms used in an application. The strategy pattern is intended to provide a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable. The strategy pattern lets the algorithms vary independently from clients that use them.

Solution 6 - Design Patterns

To add to the already magnificient answers: The strategy pattern has a strong similarity to passing a function (or functions) to another function. In the strategy this is done by wrapping said function in an object followed by passing the object. Some languages can pass functions directly, so they don't need the pattern at all. But other languages can't pass functions, but can pass objects; the pattern then applies.

Especially in Java-like languages, you will find that the type zoo of the language is pretty small and that your only way to extend it is by creating objects. Hence most solutions to problems is to come up with a pattern; a way to compose objects to achieve a specific goal. Languages with richer type zoos often have simpler ways of going about the problems -- but richer types also means you have to spend more time learning the type system. Languages with dynamic typing discipline often gets a sneaky way around the problem as well.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJorge C&#243;rdobaView Question on Stackoverflow
Solution 1 - Design Patternse-satisView Answer on Stackoverflow
Solution 2 - Design PatternsJorge CórdobaView Answer on Stackoverflow
Solution 3 - Design PatternsSupermalfView Answer on Stackoverflow
Solution 4 - Design PatternsAndrew SwanView Answer on Stackoverflow
Solution 5 - Design PatternsBill the LizardView Answer on Stackoverflow
Solution 6 - Design PatternsI GIVE CRAP ANSWERSView Answer on Stackoverflow