CSC/ECE 517 Fall 2010/ch3 3h ss
The Strategy Pattern
The Strategy pattern is one of the most common design patterns. Its main idea is to define algorithms into familial groupings. The idea is to encapsulate each algorithm, then make those algorithms interchangeable. The Strategy design pattern allows each of the algorithms to differ autonomously from the various clients that use them.1 This allows those clients to be coupled to an interface not an implementation. At any time, the system can be expanded to allow multiple client implementations without changing the interface. As you can see in the diagram below, the client communicates with the interface, which then chooses the implementation based upon its strategy.4
There are many real life examples of this design pattern being used. One that comes to mind would be opening a file. The interface is the Open command of some software. The implementations would be each of the various file types supported by the software. There would be an implementation for text file, an implementation for a comma delimited file, an implementation for a bitmap, and so on.
In the following sections we will compare how the Strategy pattern can be implemented in static and dynamic languages, and then explore if Ruby has an advantage with this design pattern because of its dynamic nature or because of the features of Ruby.
Static Languages
The use of the Strategy design pattern in static languages requires the relations between classes and interfaces to be referenced by extending classes, implementing interfaces, instantiating objects, invoking methods, etc.2 The code in the hyperlinks below show various languages implementing the Strategy design patterns.
Java
Java Strategy design pattern example. This code identifies an interface for the related algorithms and shows the use of classes to implement the individual algorithms.4
C++
C++ Strategy design pattern example. This code uses a base class as the interface and "subclasses" to implement the individual algorithms.4
Dynamic Languages
The use of the Strategy design pattern in dynamic languages requires a variable that has a function as the value. Separate classes are not needed in dynamic languages.3 Each version of the algorithm is implemented as a different object which is then varied by supplying alternative strategy objects to the context.5
PHP
PHP Strategy design pattern example. This code uses a context class that will identify the strategy based upon an input parameter.4
Ruby
class Context def initialize(&strategy) @strategy = strategy end def execute @strategy.call end end a = Context.new { puts 'One strategy for the context' } a.execute b = Context.new { puts 'Another strategy for the context' } b.execute c = Context.new { puts 'An additional strategy for the context' } c.execute
As in the PHP example, this code uses a context class that will identify the strategy based upon an input parameter.
What is Ruby's advantage?
Ruby's advantage with the Strategy pattern is two fold:
1. Dynamic languages have a clear and distinct advantage over static languages in general. There are are not as many language limitations, a smaller amount of bookkeeping of objects and classes is needed, and design is not class restricted.3
2. Ruby specific features such as duck typing and code blocks.
With both of these advantages, Ruby has the ability to utilize the Strategy Pattern quickly and cleanly. Ruby has a distinct advantage because of its built in features and because it is dynamically typed.
References
(1) Freeman, Eric & Freeman, Elisabeth. Head First Design Patterns. O'Reilly, 2004.
(2) OBJECTED-ORIENTED DESIGN PATTERN DETECTION USING STATIC AND DYNAMIC ANALYSIS IN JAVA SOFTWARE
(3) Design Patterns in Dynamic Programming
(5) Olsen, Russ. Design Patterns in Ruby. Addison-Wesley Professional, 2007.