The Strategy Design Pattern

3 minute read,

Today, I’m going to write about the strategy design pattern and give some examples on where it should be used and why it’s useful. I’m really sleepy, only had 3 hours of sleep, so I hope I can do this quick and off the top of my head.

The Problem and Design Smell

Suppose we have the following class hierarchy:

We have an abstract Animal class, that has two virtual methods Eat() and MakeNoise(). Both household Cat and household Dog classes inherit from Animal, along with inheriting behavior animal behavior. Inheriting behavior typically leads to bad design and maintainability. Let’s look at the code implementing the classes:

When we run these classes, we get the following output:

The problem (‘design smell’) associated with this approach is simply the way we are placing the implementation of the actions Eat() and MakeNoise() inside the concrete classes. This doesn’t exactly lead to a maintainable design. For example, suppose we want to extend our animal kingdom by introducing an AllyCat class. An AllyCat might have different implementations of Eat() (eating out of the trash), but still have the same kind of MakeNoise() (moew) implementation. You might think, “well, we can just derive from the concrete class Cat, and override the Eat() method with our own AllyCat.Eat() implementation” and you’re right, you can. However, extending behavior through hierarchical inheritance should be avoided. Not only that, designs like this can lead to duplicate code.

Instead, you should compose classes with isolated algorithm implementations. The goal is to separate varying-code from non-varying code. A quick way to identify non-varying code aspects of your classes is through “has-a” relationships. A Dog “has-a” distinct eating behavior, a Cat “has-a” distinct eating behavior, an AllyCat “has-a” distinct eating behavior, so on and so forth… From our classes and implementation, we have noise behaviors and eating behaviors.

The Solution

The solution to basic problems is to implement a Strategy pattern. Consider the following architecture:

And taking a peek in some of the Cat, Ally Cat and Dog code:

All that we have done with this new architecture is delegate the “making noise” and “eating” to behavioral classes that specifically handle the task. We have delegated control to the behavioral classes. This is a much better extensible and coherent design and often leads itself to better to code reuse.

Whenever we create classes that are composed of behavioral actions, we call these compositions. Classes such as Dog, Cat, and AllyCat are compositions of behaviors and gain their behavior through composition, not inheritance. Inheritance (like the previous architecture) can lead to unintended consequences when fiddling with the superclass and is more prone to breaking existing code.

Common Uses

  1. Algorithm Families – A general case different algorithms need to run depending on a particular situation.
  2. Sorting - Used in sorting when different types of sort algorithms need to be applied to a collection. For example, List.SortBy(FirstNameStrategy)
  3. Behavioral – Used when many distinct “behaviors” are expected of derived classes.

Naming Keywords for the pattern

When naming your interfaces, here are some keywords to include in the naming of your strategy:

  • General: Strategy, Algorithm
    • Example: CaliforniaTaxStrategy
  • Behavioral: Behavior, Action, Style
    • Example: BarkBehavior    

Principals to take away from this strategy

  • Look at your application, and analyze the classes that are producing the Design Smell. Take those classes, and analyze the functionality of the classes that are producing this type of Design Smell. Create a separation of varying code and non-varying code (such as specific behaviors that tend to stay the same across all classes or with every new requirement). Once you’ve identified the non-varying code, then you have an opportunity to extract the behavior from the class and isolate it in its own behavioral family.

  • Use composition rather than inheritance. Composition is encapsulating several behavior/strategies in one class to perform its work. Classes should not inherit their behaviors from base classes; instead they should be composed of behaviors/strategies.

  • Has-A relationships are good indicators that strategy pattern can be used.      

Formal definition of the strategy pattern

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

This blog post is a little dry because I’m really sleepy, I’ll try updating it to make it a little more clear later when I have more time. But I hope some of you understand! Later I’ll show you how to improve this architecture.


Damien R

I disagree with your implementation.
A AllyCat is not a Cat and I think you should have only a Cat class which take only a Food strategy.

Leave a comment

Your email address will not be published. Required fields are marked *