JavaScript Design Patterns: Strategy
Table of Contents
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.
Formal Definition
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
- Policy
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 run
, walk
, and swim
methods. After all, what if suddenly the character needs to fly
or 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:
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 walking
and running
and then write new code specifically for swimming
. And of course if walking
and 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.
Now when we want to tell our character to move in a different way we’ll just update which Movement object its currently referencing.
In practice you might have something that looks like this:
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!
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.
Here we see that brushes.outline
, brushes.square
, and 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.square
and 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:
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.
Live Example
Grab the Example Source
Related Patterns
- 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).
Table of Contents
Thanks for reading! If you have questions or feedback please leave a comment below. - Rob
You should follow me on Twitter here.