CSC/ECE 517 Fall 2010/ch3 3h PW
The Strategy pattern in static and dynamic languages
What is the Strategy Pattern
The strategy design pattern is a type of object oriented design pattern. The main purpose of the strategy pattern is to separate out the object from how it behaves so that it can be changed at runtime. To do this, we remove inheritance from the code and extract out the behaviors, or algorithms, that are different between otherwise similar objects of a particular type. We then encapsulate each of the different algorithms into a separate class, closure, or module, called a strategy. At runtime, the objects behavior is chosen and specified, and can be easily modified according to factors that may not be know when creating the classes.
Class Diagram Supporting the Strategy Design Pattern
The following drawing supports the examples below.
Advantages of using the Strategy Pattern
There are some advantages to using the strategy design pattern over other design options.
+ Each of the different behaviors, or algorithms, of an object can be managed in separate classes/closures/modules, bringing clarity and separation to the code. By pulling out the algorithms, the behaviors are easier to find and identify.
+ Normally, when using multiple similar objects that are different only in the behaviors they have, the application would have required many separate classes with a lot of code duplication. Using the strategy pattern, the code could be reduced down to a single class using several strategies.
+ Also, when the behaviors need to be modified, they only need to be modified in one place as opposed to the number of classes where the behavior is used.
How to Implement in a Static Language
The static languages implement the strategy pattern by creating a class and inside of that class is a reference to an action class. This action class is usually a superclass, that way one of the actual types of actions to be perform can be assigned. These actions are essentially subclasses of the action class. In java, we can use the abstract type interface which means any class that implements it must define each of the abstract functions. In the example below, the main object is the BasketballPlayer class. In that class is a reference to the Action interface. The Action interface has an abstract method perform. There are 3 classes that implement the Action class. They are Pass, Dribble, and Shoot. Each of these methods defines the method perform and then does that action. The BasketballPlayerExample class shows how to instantiate the BasketballPlayer class and then define different actions for it.
Example
Java Code
interface Action { void perform(); } // Implements the algorithm using the strategy interface class Dribble implements Action { public void perform() { System.out.println("Player is dribbling"); } } class Pass implements Action { public void perform() { System.out.println("Player is passing"); } } class Shoot implements Action { public void perform() { System.out.println("Player is shooting"); } } // Configured with a ConcreteStrategy object and maintains a reference to a Strategy object class BasketballPlayer { private Action action; // Constructor public BasketballPlayer(Action action) { this.action = action; } public void perform() { action.perform(); } } //BasketballPlayerExample test application class BasketballPlayerExample { public static void main(String[] args) { BasketballPlayer bballPlayer; // Three contexts following different strategies bballPlayer = new BasketballPlayer(new Dribble()); bballPlayer.perform(); bballPlayer = new BasketballPlayer(new Pass()); bballPlayer.perform(); bballPlayer = new BasketballPlayer(new Shoot()); bballPlayer.perform(); } }
How to Implement in a Dynamic Language
Dynamic languages implement the strategy pattern by extracting out the different behaviors of the main action method into individual classes or modules. In the example below, the main object is the BasketballPlayer class. In the example below, modules are used to encapsulate the three actions. They are Pass, Dribble, and Shoot. Each of these modules defines the method perform and then does that action. The instantiations at the end show how to create the BasketballPlayer objects and use them to perform the actions defined in the modules.
Examples
Ruby code
#Class to be instantiated for use in the Strategy pattern class BasketballPlayer def initialize(&action) @action = action end def perform @move.call end def method_missing(method_name) puts "#{action} is not a known b-ball play" end end #The Strategies - the modules that implement the different behaviors that our object would use module Pass def pass puts"Player is passing!" end end module Dribble def dribble puts "Player is dribbling!" end end module Shoot def shoot puts "Player is shooting!" end end #Lets test the strategy pattern bballPlayer = BasketballPlayer.new(dribble) offense.perform #=>Player is dribbling! bballPlayer = BasketballPlayer.new(pass) defense.perform #=>Player is passing! bballPlayer = BasketballPlayer.new(shoot) offense.perform #=>Player is passing! ...
Ruby Code using Blocks
#Class to be instantiated for use of the Strategy Pattern class BasketballPlayer def initialize(&action) @action = action end def perform @action.call end end #Lets test the strategy pattern #By using blocks of code, classes or modules do not need to be created and the methods do not need to be declared. a = BasketballPlayer.new { puts 'Player is passing!' } a.perform #=> Player is passing! b = BasketballPlayer.new { puts 'Player is dribbling!' } b.execute #=> Player is dribbling! c = BasketballPlayer.new { puts 'Player is shooting!' } c.perform #=> Player is shooting!
Strategy Pattern Compared to State Pattern
Another design pattern that is in use is the state pattern and it is actually very similar to the strategy pattern. With the state pattern, the object's actions or algorithm still can be changed and it is created in a separate class. The difference is that the state will change over time and as it changes the behavior automatically changes as well. So, with the State pattern the behavior changing is done automatically, and the Strategy pattern requires the client that created the object to assign a new action or behavior.
References
[1] Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates; 'Head First Design Patterns', O'Reilly, 2004
[2] Strategy Pattern Wikipedia Entry