Strategy and Command Design Patterns — Wizards and Sandwiches — Applications in Python

It’s been a while since my last post … I’ve moved cities (Vancouver, BC to Toronto, ON) and jobs. So, I wanted to get back into posting here with a simple article on two types of design patterns for Python.

Implement different strategies for your objects.

I’m also going to trying out hosting my code snippets in GitHub so they are easier to read, rather than struggling with formatting code blocks that inevitably get caught up spacing issues due to screen widths.

Why Use A Pattern?

This might be a review for most people, but using a software design pattern (should) helps in solving complex problems. Generally, the problem you’re trying to solve has a known solution or suggested method of solving. Meaning, you can spend more time on implementing the solution rather than searching for one or even creating one yourself.

Additionally, these patterns should provide us with the ability to update our project if the requirements change without fundamentally altering the core structure of the code.

In essence, our code is open for extension, closed for modification.

The Strategy Pattern

The main goal of this pattern is to switch out the same method to fit different situations, due to the encapsulation of the different strategy objects. From the image below our Strategy class has a AlgorithmInterface() method which is implemented differently by the classesConc reteStrategyA, ConcreteStrategyB, and ConcreteStrategyC. To put things in perspective, I’ll show how this could be applied to something I’m rather familiar with … RPG characters. In particular, wizards.

Not as exciting as a wizard … but good reference

You can have different kinds of wizards that have special abilities according to their type, cast different spells, and use different weapons. However, all wizard — at least the wizards we’ll be making — have a few things common to them. These are casting spells — use_magic() — and attacking — use_weapon().

While we can create subclasses of each different wizard type, we know the thing that will be different to each of them will how they implement the use of the use_magic() and use_weapon() method. We don’t care how they implement them, just that they are implemented.

We’ll use the strategy pattern to swap in and out different abilities (strategies) for each subclass of Wizard, instead focusing on each of the object’s implementation of the abilities.

To put it in terms of design principles, we’ll be “programming to an interface, not an implementation.” And, in doing do reduce the coupling between our objects.

Defining our Strategies

First, we need to define the abilities (strategies) of a Wizard. As mentioned above, they will use some sort of weapon along with a few various spells. These spells have been split into two different strategies, offensive and defensive, and will be used to show inheritance between strategies and perform type checking — as much as Python will provide — on each of the Wizard’s spells and weapons.

We’re also going to be using abc.ABCMeta to program the interface for our spells and weapons. Without going too deep, on the specifics of this is beyond the scope of this article however a good refresher can be found here.

Because we’re going to worry out the implementation of each strategy later but want to ensure they are implemented we will abc.abstractmethod decorator on our base interface. A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden. Meaning when we’re creating our new spell and weapon strategies, they must override use_magic() and use_weapon() respectively.

Because of the above, we don’t need to raise NotImplementedError for our abstract methods, because having a metaclass of abc.ABCMeta will throw an error for us if this is not implemented correctly.

Just another wizard …

We’re also going to be creating a NULL strategy for weapons and for spells, as we might have some wizards which do not use weapons or uses fewer spells than others. We don’t want to have an error thrown when the Wizard object is created without a spell or weapon assigned to it so we’re just using the same patterning but implementing a strategy where nothing occurs.

Just as a note if you instantiate the base strategy or derived strategies without implementing the abstract method, you’ll get this error:

TypeError: Can't instantiate abstract class <<ClassName>> with abstract methods <<method_name>>

From the gist below, our basic strategy MagicStrategy() has a use_magic() method and we’ll be using this to create our different spells. but if implemented from this strategy nothing will happen and we’ll get an error at run time.

We have created three interfaces from the basic strategy NullMagicStrategy(), OffensiveMagicStrategy(), and DefensiveMagicStrategy() that will allow us to further customize how our wizards behave.

The NullMagicStrategy() allows us to give a wizard no spells, without an error being thrown. While the other two, will allow us to split our wizard’s abilities (strategies) by further defining them.

The IceOffensiveMagicStrategy() will implement OffensiveMagicStrategy() and HealDefensiveMagicStrategy() will implement DefensiveMagicStrategy().

To create a further implementation of a strategy you simply have to make sure the new interface inherits from a previous interface, and implement the abstract methods.

class OldInterface(metaclass=abc.ABCMeta):
@abc.abstractmethod
def foo():
pass
class NewInterfaceToCreate(OldInterface):
def foo():
print('foo')

Making Our Wizards

Or basic wizard has one attribute for a weapon and three attributes for spells. But what about wizards that are more specialized? Say, a wizard who uses fire spells or one that is devoted to healing?

Because we have our strategies sorted out before our wizards are created, we can easily create a base wizard class, define what types of spells or weapons we want them to use, and swap in different strategies as we see fit, rather than rewriting large chunks of code.

Alternatively we could only use a base Wizard and simply swap in strategies, however I wanted to show how these strategies could be used along with inheritance.

The strength of the strategy pattern should become apparent here, as when we start swapping in different spell or weapon patterns, each strategy has a common interface to be called. This allows any instantiated wizard object to use self.weapon_slot.use_weapon() or self.weapon_slot.use_spell_slot_2() and return the result of the strategy implemented there.

When a base wizard object is initialized, we can assign one weapon strategy and three spell strategies. Our base Wizard can use any type of weapon they want and any type of spell they want, but has no custom abilities.

Take our FireWizard, they have one slot for any offensive spell type they want when instantiated, but as assigned by default a sword, two fire offensive magic spells, and a class specific method cast_ring_of_fire().

Alternatively, our HealingWizard has no free spell attributes, is assigned a staff as a weapon, two healing magic spells, a null spell in their third slot, and a class method cast_mass_healing() which is specific to them.

Assigning Strategies to Wizards

Now that we have defined our strategies and the wizards to implement them, let’s test out our code. We’re going to create different strategy objects, and assign them to a FireWizard and a HealingWizard.

Notice how we can quickly instantiate two different FireWizard objects, that have different strategies for their self._spell_slot_3.use_magic(), yet both use the same method calls? That’s the speed and efficiency of the strategy pattern at work.

# Instantiate strategies
foms = FireOffensiveMagicStrategy()
mmoms = MMOffensiveMagicStrategy()
hdms = HealDefensiveMagicStrategy()
staff_ws = StaffWeaponStrategy()
sword_ws = SwordWeaponStrategy()
null_magic = NullMagicStrategy()
null_weapon = NullWeaponStrategy()
# Create wizards
fw = FireWizard(mmoms)
fw2 = FireWizard(foms) # Assigning an additional fire spell
hw = HealingWizard()
# Test spells
fw._spell_slot_3.use_magic()
fw2._spell_slot_3.use_magic()
hw._spell_slot_3.use_magic()
hw.cast_mass_healing()
>> Casting MAGIC MISSILE spell
>> Casting FIRE spell
>> No spell assigned
>> Casting MASS HEAL

We can still assign the wrong spell to our wizards despite Python3’s limited type checking to assign our wizards different types of spell strategies.

What we would expect to happen if we try to assign an additional weapon to one of the spells slots is an error will be thrown, or if we try to assign a defensive spell to an offensive spell attribute. This is not the case because of the limited type checking in Python. That being said, you can implement some strategies to protect against this. However, those are beyond the scope of this article.

# Create a fire wizard with healing spellfw2 = FireWizard(hdms)
fw2._spell_slot_3.use_magic()
>> Casting HEAL spell# Assigning hdms to the fire wizard was not caught during runtime

Just as a quick a side note, we can quickly create additional wizard interface (SummonerWizard) on the fly by dynamically creating classes using the built-in type method. This is essentially a dynamic form of defining a class, and more on that here. It’s not necessary by any case, but allows us to see a different way in creating and instantiating classes.

class SummonOffensiveMagicStrategy(OffensiveMagicStrategy):
def use_magic(self):
print('Casting SUMMON spell')
soms = SummonOffensiveMagicStrategy()SummonerWizard = type(
'SummonerWizard', # Name of new Wizard
(Wizard, ), # Inherit interface
{
'cast_final_summon': # New method
lambda x: print('Casting FINAL SUMMON')
}
)
# Create SummonerWizard instance and assign strategiessw = SummonerWizard(null_weapon, soms, soms, soms)
sw.use_weapon()
sw.cast_final_summon()
sw.use_spell_slot_1()
>> No weapon assigned
>> Casting FINAL SUMMON
>> Casting SUMMON spell

I hope that was fairly straightforward, and you now know how to use this design pattern in a manner that is a bit more accessible than just looking at the class diagram.

Command Pattern

Now for something a little different, as we’re moving away from tabletop gaming and into the kitchen. We’ll be using this setting, and the food prepared in it, to explain the command pattern.

This pattern is great to encapsulate method invocations and to decouple the invoker of a method from the receiver of the invocation. But what does that mean, exactly?

There is also a subtle difference between the terms invoke and execute use in the rest of the article, and this is the use of dependencies. In the case where execute is called, this implies your method will get executed, however, if a method is invoked, will call an entire chain of methods including the dependencies. This difference will be important for understanding how the command pattern works.

As well, while not strictly pythonic we’re going to be using a form of dependency injection (DI) when creating our classes. There is a good article here which goes into more of the details of this pattern.

# Dependency injection e.x. 1

class Foo:

def __init__(self, bar: Bar):
self._bar = bar # Class 'Bar' is injected
# Dependency injection e.x. 2class Person:def __init__(self, profession: Profession):
self._profession = profession # Class 'Profession' is injected

You can see how both our Foo and Person classes both require a separate class (Bar or Profession) before they can be instantiated. Meaning they are dependent on these objects.

This is important, because creating objects directly within a class creates inflexible code which is hard to refactor. Using DI, the class becomes more reusable when it interacts with other classes, and makes things easier to test.

Now, back to the command pattern….

Let’s break down the various parts of this pattern before we get into how we’re going to implement it:

  • A Command declares an interface for execute();
  • A Receiver to for the specific method;
  • A ConcreteCommand extends the Command interface, implementing the execute(). As well, the Receiver is injected into the construction of this class;
  • A Client creates ConcreteCommand object and sets its Receiver, and will use the invoker to invoke() our ConcreteCommand, and;
  • An Invoker which will invoke each Command to carry out the request(s).
Command pattern as a class diagram

First we need to create a Command which is an interface for executing a method. In this case, the method is execute(). The same way we declared a spell and weapon interface above with abc.ABCMeta, we’ll do it again here for this command.

Then we create a ConcreteCommand which extends the Command interface, implements execute(), and a Receiver is injected into the construction of the object.

None of this makes any sense without context. So let’s take a look at how we could make some lunch. Who does not like lunch?

In this case the class Sandwich (our Receiver) will hold the make_sandwich() but it will not directly call this method. We want to call execute() directly through an Invoker which will then call make_sandwich().

# Call chain from the InvokerInvoker.invoke() --> Command.execute() --> specific_command() --<<Something happens>>

Next, our class SandwichCommand — which implements Command — will inject Sandwich as a parameter during instantiation.

# Create a Receiver, and a ConcreteCommand with Receiver as parametersandwich = Sandwich()  # Receiver
command_sandwich = SandwichCommand(sandwich) # Injection

Before we get into the Invoker object, let’s take a look at the whole body of our command pattern to set ourselves straight about the code mentioned above.

Our Invoker — without too much ceremony we’ll call ours MealInvoker — will invoke() the execute() method indirectly through a Command, and therefore make our sandwich. And the key point here is the Invoker does not care what type of command it is being executed.

Additionally, with our MealInvoker we can ask it to invoke a list of commands by adding them to a list to be called sequentially later.

Command Pattern So Far

Here are the steps with our command pattern:

Remember how at the beginning of this section I mentioned this pattern “decouple(s) the invoker of a method from the receiver of the invocation”, now you should be able to see clearly how our Invoker calls invoke() which in turn calls execute() on a ConcreteCommand, and finally the Receiver calls its specific method — make_sandwich() — completing the operations.

Let’s see how our command class works in practice

# Command pattern in actionsandwich = Sandwich()  # receiver
command_sandwich = SandwichCommand(sandwich) # concrete command
salad = Salad() # receiver
command_salad = SaladCommand(salad) # concrete command
meal_invoker = MealInvoker(command_sandwich) # invoker
meal_invoker.invoke() # Starting the method calls
meal_invoker.add_command_to_list(command_salad)
meal_invoker.add_command_to_list(command_sandwich)
meal_invoker.add_command_to_list(command_salad)
meal_invoker.execute_commands()
>> A sandwich is being made
>> A salad is being made
>> A sandwich is being made
>> A salad is being made

Final Thoughts

As I said earlier, it has been a while since I posted about anything. The move was a lot more than I expected … especially moving across the country. But I’m all settled in and I hope to be posting more and more over the coming months.

Thanks for reading, and I hope you learned something new.

Cheers

Additional Reading

Robert R.F. DeFilippi

Written by

Sometimes Chef ◦ Sometimes Data Scientist ◦ Sometimes Developer

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade