How does the Strategy Pattern work? [closed]

Solution 1:

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:

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:

  • 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;