Summary
This post describes how the Strategy Design Pattern lets a variety of different algorithms be used interchangeably as well as how it relates to the Open-Closed Principle. You can read my previous article discussing the Strategy Design Pattern and Dependency-Inversion Principle. Some information is repeated here on purpose from the previous article, because it shows how the Strategy Design Pattern helps your applications implement several object-oriented principles.
Open-Closed Principle
In a recent post I talked about the Open-Closed Principle as discussed in the the book, Agile Software Development - Principles, Patterns, and Practices by Robert Martin. The Open-Closed Principle is one of five object-oriented programming principles associated with class design:
Modules that adhere to this Open-Closed Principle have 2 primary attributes:
- "Open For Extension" - It is possible to extend the behavior of the module as the requirements of the application change (i.e. change the behavior of the module).
- "Closed For Modification" - Extending the behavior of the module does not result in the changing of the source code or binary code of the module itself.
How This Relates to the Strategy Design Pattern
As discussed earlier with the Dependency-Inversion Principle, two design patterns that can help you implement the Open-Closed Principle in your applications are the Template Method and Strategy Design Patterns. These two design patterns are all about hiding the specifics of an algorithm either via Inheritance (Template Method) or delegation (Strategy Pattern).
The Strategy Design Pattern delegates algorithm specifics via an Interface.
Example of Strategy Pattern in the .NET Framework
A great example of the Strategy Pattern in the .NET Framework is the sorting of objects in an ArrayList via the IComparer Interface.
By default, the Sort method on ArrayList uses the QuickSort algorithm along with the IComparable implementation of each item in the list for sorting.
However, at times it may be necessary to sort the list in different ways. To accomplish this, there is an overload of Sort that takes an IComparer as a parameter. If used, ArrayList uses IComparer.Compare for the comparisons. By passing in an object that implements IComparer, the ArrayList can implement other sorting methods without caring about the details of the comparison method.
This is an example of the Strategy Design Pattern. Hiding the details of the comparison method behind an Interface allows the algorithm to vary and keeps the ArrayList from being dependant on the classes that implement such algorithms.
How This Relates to the Open-Closed Principle
This supports the Open-Closed Principle because implementing a new comparison method for sorting objects in an ArrayList does not require a change to the ArrayList Class. This class is essentially closed for modification. However, because we can pass in an object that implements IComparer, the class is open for extension. Extending this class only requires new code ( classes ) to be written that implement IComparer, not changes to existing code.
Conclusion
The Strategy Design Pattern is a pretty powerful and often used design pattern to loosely couple your main classes in an application from lower-level detail classes / algorithms. As with all design patterns, it is best not to use them just for the sake of using them, because you will run the risk of needless complexity (application design smells) in your applications. They are best thought of as a solution to a real problem that occurs during refactoring and a method of communicating how the problem was solved.