Strategy Design Pattern and Dependency-Inversion Principle

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 Dependency-Inversion Principle.

 

Dependency-Inversion Principle

In a recent post I talked about the Dependency-Inversion Principle discussed in the the book, Agile Software Development - Principles, Patterns, and Practices by Robert Martin.  The Dependency-Inversion Principle is one of five object-oriented programming principles associated with class design:

 

Dependency-Inversion Principle

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.

 

The principle suggests you can make your applications loosely coupled (Low Coupling GRASP Pattern) by not depending on concrete classes, but abstractions. This principle points out the direction of dependency on the abstraction. Rather than having the policy and business level classes dependent on the lower-level plumbing / utility type detail classes, it recommends that you invert the dependency and make the lower-level detail classes dependent on the higher level policy making classes that are most important in your application (via an abstraction).

 

 

How This Relates to the Strategy Design Pattern

Two design patterns that can help you implement the Dependency-Inversion 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.

 

Strategy Pattern with IComparer

class CoolComparer : IComparer
{
    #region IComparer Members

    public int Compare(object x, object y)
    {
        // TODO:  implementation
        return 0;
    }

    #endregion

}


ArrayList items = new ArrayList();

items.Add("One");
items.Add("Two");
items.Add("Three");

items.Sort(); // Uses IComparable on string object

IComparer myComparer = new CoolComparer();
items.Sort(myComparer); // Delegate Comparison Method

 

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.

 

posted on Monday, June 27, 2005 7:54 PM

Main

News

Green Tea

.NET Development

Enterprise Library

Patterns & Practices