- It defines a family of algorithms and encapsulates each algorithm.
- Strategy makes them interchangeable and lets the algorithm vary independently from clients that use it.
- Its intent is to encapsulate alternative strategies for a particular operation.
- The Strategy pattern is a "plug-and-play" pattern.
- The client calls a method on a particular interface which can be swapped out with any other Strategy class that implements the same interface.
- If the Strategy interface has only a single method you can simplify the implementation by using a delegate (or
Func
) rather than an interface.
- A delegate is a special case of the Strategy pattern.
- .NET's event model (which uses delegates as event handlers) is built also on the Strategy pattern.
- You can also achieve the strategy pattern using "property injection"
- You can pass strategy using a method or the constructor.
- An example of the Strategy pattern in .NET is the
ArrayList
which contains several overloaded Sort methods.
- These methods sort the elements in the list using a given class that implements the
IComparer
interface.
IComparer
contains a Sort method that compares two objects and returns a value indicating whether one object is greater than, equal to, or less than the other object.
- Classes that implement the
IComparer
interface are implementations of the Strategy design pattern.
Participants
Strategy
(ISortStrategy)
- Declares an interface common to all supported algorithms.
- Context uses this interface to call the algorithm defined by a ConcreteStrategy.
ConcreteStrategy
(SortAsc, SortDesc)
- Implements the algorithm using the Strategy interface.
Context
(CustomList)
- Is configured with a ConcreteStrategy object.
- Maintains a reference to a Strategy object.
- May define an interface that lets Strategy access its data.
private static void Main()
{
var studentRecords = new CustomList();
studentRecords.Add("Samual");
studentRecords.Add("Jimmy");
studentRecords.Add("Sandra");
studentRecords.Sort(new SortAsc());
studentRecords.Sort(new SortDesc());
}
public interface ISortStrategy
{
void Sort(List<string> list);
}
public class SortAsc : ISortStrategy
{
public void Sort(List<string> list) => list.Sort();
}
public class SortDesc : ISortStrategy
{
public void Sort(List<string> list)
{
list.Sort();
list.Reverse();
}
}
public class CustomList
{
private List<string> _list = new List<string>();
private ISortStrategy _sortstrategy;
public void Add(string name) => _list.Add(name);
public void Sort(ISortStrategy sortstrategy) => sortstrategy.Sort(_list);
}
Rules of Thumb
- Strategy is like Template Method except in its granularity.
- State is like Strategy except in its intent.
- Strategy lets you change the guts of an object.
- Decorator lets you change the skin.
- 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.
- Strategy has 2 different implementations, the first is similar to State.
- The difference is in binding times (Strategy is a bind-once pattern, whereas State is more dynamic).
- Strategy objects often make good Flyweights.