Strategy Design Pattern
Software Engineer II currently working at Akamai Technologies. Full Stack Web Development and DevOps enthusiast.
Definition : Formally, strategy design pattern can be defined as a design pattern that defines a family of algorithms and put them into separate classes so that they can be changed at run-time.
Lets understand strategy design pattern with help of an example :
We have a creature class, that acts as a base class for defining creatures like human , bird, animal etc. Lets consider that creature class has walk, talk, appearance member functions. The UML diagram will look like :

Creature is an abstract base class and have only declaration of member functions
walk,talkandappearance.Human,InsectsandAnimalare the the concrete implementations inherited fromCreatureThe inherited classes have defined the member functions. Each child class can have it’s own version of member function definition.
Suppose, now we have to create another creature : bird having a fly member function along with the existing member functions.
Option 1 : We can add fly in the base class, so that all the child classes have inherited fly member function.

What’s wrong with above approach ?
Human,Insectsdon’t needflymethod. Still they will inheritflymethod, which is incorrect.Humans cannot fly.
Some insects can fly but lets assume that insects don’t fly.
Although, we can define
flymethod to throw error insideHumanandInsectsclass. This is acceptable but in the first place itself, we should not have inherited the fly method.
Option 2 : We can define another abstract class flyable_creature that inherits from Creature class. The flyable_creature class will inherit all the member functions of creature class and also add another member function fly. Now, we can inherit bird from flyable_creature class.

All the objects now only have relevant methods.
This approach is correct but think about the scenario if more creatures are added with different behaviors.

Drawbacks:
The inheritance tree will keep growing.
Whenever a new creature is created with some different member function, the class structure needs to be modified.
Breaking open close principle.
Violating DRY principle(do not repeat yourself).
How does Strategy Design pattern overcome these drawbacks?
From the definition, we know that strategy design pattern is a design pattern that defines a family of algorithms and put them into separate classes so that they can be changed at run-time.
We can consider
walk,talk,flyandappearanceas different algorithms and put them into separate classes.The
Creatureclass will have reference to the interfaces of these algorithms.The concrete class is determined during run-time.

Strategieshave been defined :Talkable,Walkable,FlyableandAppearable.Each strategy is an interface (interface is implemented using abstract class in python).
The concrete implementations can extend their respective interface and define the abstract method.
Creatureis coded against the interfaces and not against the concrete classes.The actual
walk,talk,flyandappearancemethod is determined at run-time.
Implementation of Strategy Design Pattern in Python
from abc import ABC, abstractmethod
# Interfaces declaring different Strategies
class Talkable(ABC):
@abstractmethod
def talk(self):
raise NotImplementedError
class Walkable(ABC):
@abstractmethod
def walk(self):
raise NotImplementedError
class Flyable(ABC):
@abstractmethod
def fly(self):
raise NotImplementedError
class Apperable(ABC):
@abstractmethod
def appearance(self):
raise NotImplementedError
# Concrete implementation of these strategies
class NoTalk(Talkable):
def talk(self):
print("I cannot talk")
class CanTalk(Talkable):
def talk(self):
print("I can talk")
class NoWalk(Walkable):
def walk(self):
print("I cannot walk")
class CanWalk(Walkable):
def walk(self):
print("I can walk")
class NoFly(Flyable):
def fly(self):
print("I cannot fly")
class CanFly(Flyable):
def fly(self):
print("I can fly")
class NoApperance(Apperable):
def appearance(self):
print("I donot appear")
class CanAppear(Apperable):
def appearance(self):
print("I can appear")
# Define the client (in this case creature)
class Creature:
def __init__(self, t : Talkable, w : Walkable, f : Flyable, a : Apperable):
self.talkable = t
self.walkable = w
self.flyable = f
self.apperable = a
def walk(self):
self.walkable.walk()
def talk(self):
self.talkable.talk()
def fly(self):
self.flyable.fly()
def appearance(self):
self.apperable.appearance()
if __name__ == "__main__":
human = Creature(CanTalk(), CanWalk(), NoFly(), CanAppear())
human.talk()
human.walk()
human.fly()
human.appearance()
bacteria = Creature(NoTalk(), CanWalk(), NoFly(), NoApperance())
bacteria.talk()
bacteria.walk()
bacteria.fly()
bacteria.appearance()
Output:
I can talk
I can walk
I cannot fly
I can appear
I cannot talk
I can walk
I cannot fly
I donot appear
Conclusion
Encapsulate what varies and keep it separate from what remains same.
Solution to inheritance is not more inheritance.
Composition should be favored over inheritance.
Code to interface and not concrete implementation.
Do not repeat yourself.
