Design Patterns in Python Part 1: The Strategy Pattern

Sheikh Sajid
3 min readNov 15, 2017

--

What are design patterns?

Most programmers are faced with a number of recurring problems as they write object oriented code. In an attempt to standardize the solutions to these problems, four software engineers, during the 90’s, got together and identified the most common patterns of problems that occur in object oriented programming. Then they formulated model solutions to these common problems in a book called “Design Patterns: Elements of Reusable Object-Oriented Software” aka “The Gang of Four (GoF)”. It is still the authoritative reference for everything relating to software design patterns.

In layman's terms, A Design Pattern describes a problem and a general approach to solving it.

If we use design patterns, our programs will be easily understandable and extensible by those who come after us.

Classification of Design Patterns

  1. Creational Patterns: These are concerned with creating objects
  2. Structural Patterns: These patterns describe relationship between objects
  3. Behavioral Patterns: Interaction between different objects

The Strategy Pattern

The strategy pattern (aka “The Policy Pattern) is one of the most frequently used Behavioral Pattern out there. It is also one of the simplest.

The main goal of this pattern is to enable a client class to choose between different algorithms or procedures to complete the same task. This way, different algorithms can be swapped in and out without complicating things. To do this, a number of Strategy classes are created that have the same interface and contain the implementation details of the specific algorithms.

It decouples the client class from the class that is actually implementing the details of the algorithm.

Photo — sourcemaking.com

You can imitate this functionality using inheritance as long as the number of algorithms and sub classes are limited. But, more often than not, composing an object from different strategies is better than creating a complex inheritance hierarchy. This might result in a explosion of classes caused by subclassing for every possible combination of procedures or algorithms.

Example

Suppose, you have two types of ducks in your program, LoudDuck and GentleDuck. The LoudDuck class, in turn, has sub types VillageDuck and ToyDuck. And GentleDuck has a subtype CityDuck.

Up until this point everything looks fine. But now, your client changes her mind and wants to you to include a new type of duck, RobotDuck. She further informs you that,

  1. RobotDuck is-a LoudDuck. That’s fine, you can just inherit from the LoudDuck class.
  2. It also needs to have a “lights-on” method like ToyDuck. Now this is the tricky part. There is no straightforward way of doing this using inheritance. You cannot inherit from ToyDuck because RobotDuck does not have a is-a relationship with ToyDuck. Even if it did, ToyDuck is-a GentleDuck and RobotDuck needs to be a LoudDuck.

It is not impossible to write the program using inheritance. However, you would have to introduce many more classes and create a relatively complex inheritance hierarchy just implement this simple new feature. Also, bear in mind that this is a very rudimentary example, real world applications will usually have much more complex structures which will complicate things even further. One other option is to just copy the method from ToyDuck to RobotDuck, which is even worse.

However, if you use the Strategy pattern, you can easily implement this program with minimal effort:

Structure of the Duck class and its strategies

As you can see, we are basically taking different strategy objects and “composing” other objects by using them as the building blocks. It is similar to using different types of Lego bricks to build structures. We can do this by having the strategy objects as attributes of the Duck class. They are passed to the constructor of Duck in main.py. The strategies and their abstract interfaces are defined in strategy.py.

One other way of doing this in Python is by implementing the strategies as functions and then passing these functions to the constructors. But using interfaces is the “standard” way of taking advantage of the Strategy Pattern.

--

--