Hey, man! Listen: I’ve got a great idea to share with you. Why don’t we use circular objects supporting a plain surface in order to carry things with less effort? This way, we would just have to push a little bit and the circular objects would take care of the effort with its rolling movement. And, by the way, why don’t we call this circular object a wheel?
I know this sounds weird now, but there had to be a time when it really made a huge difference: when people didn’t know about the wheel, imagine the looks of the people when they first heard about it: they were most certainly filled with admiration, to say the least. Imagine all the effort they would save from then on…
Yes, the don’t reinvent the wheel parable. That’s what design patterns are all about: to walk on the shoulders of others that have already experienced and solved the trouble you’re going through now.
Sweat or sweet?
I have the feeling that most people talk about design patterns as if they were cool, but deep inside, they think they aren’t cool at all. And it’s perfectly understandable. How can anything be cool when its main official source is a book called Design patterns: Elements of Reusable Object-Oriented Software? Had I been the editor of the GoF’s book, I would have forced them to throw that title far, far away. Or at least, I would have left most of the title out: so many words eclipse the power of the main word in that title: reusable. But that is probably another kind of (human) pattern that I’ll leave for a future post: why do we like to sound academic instead of just helpful?
The point is, probably the pattern of all patterns lies there, naked in the beautiful, humble and simple word REUSABLE.
I have a confession to make: although I’ve studied Design patterns, I don’t have the feeling of having reached a point where I can say I’ve come to master them.
So, having said that, I’ll follow some good piece of advice someone told me once: the best way to learn something is by teaching it. So here we go!
To start out, I’ve chosen the Strategy pattern.
What is a strategy?
Let’s see Wikipedia’s definition of strategy: a general plan to achieve one or more long-term or overall goals under conditions of uncertainty (I couldn’t resist to bring up a definition like this, containing the sentence under conditions of uncertainty in a software development’s post).
Here is strategy, from a different perspective:
Although this quote comes from an entrepreneur and not from a software developer, the fact that Mr. Welch used the word implement while talking on strategy was very inspiring. So I chose to reuse his quote to let more light in.
Now, from the GoF’s book, in the Strategy pattern, we have mainly three elements:
- The context;
- the abstract strategy
- and the concrete implementations of the strategy.
Cristal clear, ain’t it? I think we need some metaphors here (at least I do and hey, it’s my blog).
Metaphors’ time
Imagine, for example, that you are a soccer manager. And, of course, as a manager you want your team to win the match (the context):
public class SoccerMatch {
private Ball ball;
public void play(){
//...
}
}
What are you going to do inside the play method to win the match? Are you going to define all the possible actions concerning the ball here in the SoccerMatch? Probably at the first stages of developing you will.
But, at refactoring time, wouldn’t it be better to have a strategy instead of the low-level ball to direct your actions? It’s time for a strategy to come into play:
public class SoccerMatch{
private OffensiveStrategy offensive;
public void play(){
offensive.score();
}
}
As a Strategy, OffensiveStrategy would be an interface, defining the action to be implemented:
public interface OffensiveStrategy {
void score();
}
And finally we would have the implementors, the concrete strategies:
public class DutchOffensiveStrategy implements OffensiveStrategy {
private Ball ball;
public void score(){
passTheBallUntilTheRivalSleeps();
shoot();
celebrate();
};
/*Implementation of the rest of the methods...*/
}
public class EnglishOffensiveStrategy implements OffensiveStrategy {
private Ball ball;
public void score(){
shootAsHardAsYouCan();
celebrate();
celebrateOnceMore();
};
/*Implementation of the rest of the methods...*/
}
And that’s it, that’s the strategy pattern in action: extract from the context (soccer pitch) the object that is usually just an ingredient (the ball), transform it into the relevant action (to score), and instead of manipulating it directly in the context, change your point of view, focusing on the high-level action, delegating this action to an implementor of the strategy.
More metaphors
Knowing when to apply the Strategy pattern is also important. Here we go, in culinary terms, from the code smell to the recipe for a good strategy pattern:
- Your code is a mess, with a mix of objects and actions, usually all scattered in one class (say, kitchen, living room, even bathroom, all in one room).
- we abstract the action that we want to get done with those ingredients into an interface (say, Cookable).
- we implement the action in different ways or specialties, depending on the gourmet’s taste (concrete classes that implement the Cookable interface, such as SpanishCookable or JapaneseCookable).
- Finally, you let the hungry customer have a handle to the cook in order to eat the food made by the cook (we’ll leave the waiter alone in the bathroom, at least for the time being).
In other words, cook whatever you want in whatever style you want. But let a specialist cook do it in the kitchen, and eat it in the dining room.
Sir, yes, sir!
As a tribute to the original etymology of the word strategy, let’s recap in military terms what the Strategy pattern is about:
- Define your General (your strategy, your interface: an abstract action that you want to be accomplished: this action would be the one in command, the general that defines what needs to be done: the interface’s method).
- Let the context (the Battlefield) depend on that general or interface, via composition. So the context has a strategy, that will be carried out by the captain that best suits the task at hand.
- Let the Captains or implementors worry about the tactics: the different captains (concrete classes) will implement the strategy in their own way.