The Strategy pattern is one of my personal favorites and you’ve probably seen or used it in some fashion without even knowing it. Its primary purpose is to help you separate the parts of an object which are subject to change from the rest of the static bits. Using Strategy objects versus subclasses can often result in much more flexible code since you’re creating a suite of easily swappable algorithms.
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
Also Known As
Contrived Example Time!
Let’s say you’re making a game and you have a Character class. This game has all sorts of different terrain types so your character can run through open fields, walk slowly through swamps or swim under the ocean. Since you don’t know what kind of other terrains the game designer is going to think up you decide that it would be a bad idea to give each character
swim methods. After all, what if suddenly the character needs to
crawl? What if they’re wounded and they need to
limp? This situation could potentially get out of hand very fast…
There’s a good chance you’ve seen or written code like this before:
1 2 3 4 5 6 7 8 9
When you see a big conditional like that or a switch statement it’s time to stop and wonder if there’s a better way. For instance if we need to subclass our Character we’re going to have to override that big conditional. What if we only want to replace the
swimming bit? We’ll have to copy and paste the code from the super class for
running and then write new code specifically for
swimming. And of course if
running ever change we’re totally screwed.
We need a Strategy to deal with this
Ok so we know that our character is going to be a real contortionist and need to run and jump and crab-walk all over the place. What if we took the code that made her run and we put it in its own object? How about we just define a Class for movements and we do this for all the different kinds of motion? Then when we need to move our Character we’ll just tell it to defer to one of these Movement objects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Now when we want to tell our character to move in a different way we’ll just update which Movement object its currently referencing.
1 2 3 4 5 6 7
In practice you might have something that looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Now it’s easy for us to add as many different kinds of motion as our little game designer can dream up. Want to give the character gas-powered robotic legs? No problem!
1 2 3 4 5 6
When to use it
When you have a part of your Class that’s subject to change frequently or perhaps you have many related subclasses which only differ in behavior it’s often a good time to consider using a Strategy pattern.
Another benefit of the Strategy pattern is that it can hide complex logic or data that the client doesn’t need to know about.
The Painting App
For a real world example of when to use Strategy objects consider your typical painting program. Often times you will offer a variety of different brush types to your user but you don’t want to have to change the fundamentals of how a mark shows up on screen every time the user decides to switch from a round to a square brush. Why not wrap those specific implementations in their own brush objects and later on when the user clicks to draw something to screen we’ll just defer to one of those brushes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Here we see that
brushes.circle each implement a consistent interface for the
draw call. However their exact implementation changes from one brush to the next.
brushes.outline will only draw the stroke of a rectangle, whereas
brushes.circle will fill their respective shapes in. Elsewhere in the program we set our initial brush to a default of brushes.square. When the users presses their mouse and moves it around screen we can defer to whichever Strategy the brush object is currently referencing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Again notice that
.on('mousemove') we first check to see if it’s ok to draw something and then defer to whichever Strategy is currently being referenced. Using this approach we can add limitless new brush types to the
brushes object and easily change how our program performs at runtime. Be sure to check out the live example and the source for the full application.
- Flyweight: Strategy objects often make good flyweights.
Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994-10-31). Design Patterns: Elements of Reusable Object-Oriented Software. Pearson Education (USA).
Thanks for reading! If you have questions or feedback please leave a comment below. - Rob
You should follow me on Twitter here.