I’ve been having a look at coding katas and design patterns over the last couple of weeks. If you are not familiar with either of these concepts then you can read Uncle Bob’s introduction to the Bowling Kata and check out Richard Carr’s great set of articles on design patterns.
My main goals are to:
- Increase my familiarity with design patterns
- Understand how design patterns can be best applied in real life situations
- Develop a repeatable method for memorizing the patterns
A good way to cover off all of these goals will be to develop a set of code kata’s which can be solved by applying a design pattern. Sounds simple? Maybe but lets get started and see how it goes!
The Strategy Pattern
The strategy pattern is defined as
“a design pattern that allows a set of similar algorithms to be defined and encapsulated in their own classes.”
The aim of this pattern is to separate the parts of a system that may change from those which are unlikely to change, allowing for easier maintainability of the system in future. This all sounds good in theory but you may be wondering how and where the pattern can be applied in practice. With this in mind I’ve come up with a fictitious brief that we can solve by utilising the Strategy Pattern.
A games company is developing a sports event simulator, to be built in iterations starting with simple requirements and building up to increase the complexity. The system design should allow for changes to be made by extending the existing system without changing what is already in place.
- The simulator must support marathon and 10 km run events. The only requirement for these events is that the competitors can be displayed in some way (text is fine) and they can compete in the event. All competitors will compete by running.
- After running some events they proved to be totally chaotic so each event should now include a marshal. The marshal can also be displayed but does not compete in events.
- Since the glorious victory of team GB in the Olympic Triathlon the sport’s popularity has increased. So the games company would now like to also support triathlon events. Again competitors must be displayed and be able to compete, however a triathlon competitor will compete by swimming, cycling and running.
Designing the Solution
The starting point for this kata is available to clone from github here: Strategy Kata Start
To meet the first requirement we only need a couple of objects as shown below:
We can create a couple of events for marathon and 10km runs and add some runners to those events. When the simulation runs the Compete() base method is called for each of the EventAttendees to simulate them taking part in the event. Each of the runners can be displayed by a call to their Render() method.
We now need to include Marshals as part of the event, so the model is extended as below:
However, there is an obvious problem with this design, as noted in the diagram. One option would be for the Marshall to override the Compete method and make it do nothing. However this will store up more trouble for us as there may be other types of event attendee later which do not compete. We would have to ensure that each of these attendees also override that method with the same ‘not compete’ behaviour. There is a better way to design for this issue (there is a clue in the name of this blog post!)
It is clear that the Compete behaviour may change frequently depending on the attendee, we can leverage the Strategy pattern to extract this behaviour into separate classes as shown below.
The EventAttendee base class now contains a property of type ICompeteBehaviour. Any implementation of this interface can be assigned to each instance of an EventAttendee. So the Runner class is assigned the Run behaviour and the Marshall class is assigned the DontCompete behaviour.
We have one more requirement to satisfy, the design needs to be extended to allow Triathlon events to take place. Thanks to our changes in the previous iteration we can add this new requirement without making any changes to the existing classes. Here is the final structure:
We have extended the EventAttendee class with a new Triathlete class and created a new RunCycleSwim implementation of the ICompeteBehaviour interface. You may be thinking that the same could have been achieved with a method for the behaviour on the Triathlete class, while this is true it limits the flexibility of the design. We can see the advantage of this design by adding Spectators to the simulation. They will also be assigned the DontCompete behaviour, so we have effectively shared this part of the logic without repeating the implementation.
The completed implementation for this kata is available on github here: Strategy Kata End