CSC/ECE 517 Fall 2010/ch3 3h az
Objective
Objective of this Wiki Chapter is that the reader should be get an overview of
- Strategy pattern, when and how to use strategy pattern.
- Implementation of strategy pattern in Dynamic, Static object oriented language by going through our example.
Introduction
A design pattern is a general reusable solution to a commonly occurring problem in software design. Strategy Pattern in one such pattern which helps to use multiple algorithms interchangeably to reduce multiple conditions statements. This helps in making the code more maintainable.
The intent of Strategy pattern would be to define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. As an algorithm evolves to handle more and more situations, it can become very complex and difficult to maintain, Strategy pattern can be used to resolve this situation.
The Strategy pattern is different form the Bridge and State pattern. Listed below are the differences and when to use each of them-
Strategy Pattern | Bridge Pattern | State Pattern |
---|---|---|
The Strategy pattern deals with USING different implementations to implement
different algorithms. Strategy pattern is meant for behavior. |
The Bridge pattern deals with HOW you deal with multiple implementations. The Bridge pattern is meant for structure. | The State pattern deals with HOW you switch between different states/implementations |
One way to implement the Strategy pattern is to use the Bridge pattern approach or the State pattern approach, but the strategy pattern can also be
implemented a number of other ways. |
You cannot use the strategy pattern to implement bridge pattern. | You cannot use the strategy pattern to implement state pattern. |
When to use Strategy Pattern
- Many related classes differ only in their behavior.
- You need different variants of an algorithm. For example, defining different algorithms based on space-time tradeoffs.
- A class defines many behaviors, and these appear as multiple conditional statements in its operations.Instead, move related conditional branches into their own Strategy class.
Components in the implementation of a Strategy pattern:
Strategy:
- Declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy.
ConcreteStrategy:
- Implements the algorithm using the Strategy interface.
Context:
- Is configured with a ConcreteStrategy object
- Maintains a reference to a Strategy object
- May define an interface that lets Strategy access its data.
Illustration of Strategy pattern through real world example
To illustrate strategy pattern let’s consider this example of basic file transfer scenario, where we want to compress the file before transmission. File compression can be achieved by different algorithms for different types of file. Image files and text files can be compressed by different algorithms, here we would like demonstrate how this algorithm can be encapsulated and helps in selecting the algorithms without the conditional statements.
The following UML class diagram captures the scenario we are illustrating:
ApplicationObject would be having instance of IcompressStrategy. IcompressStrategy is the common interface and defines generic algorithmic method which would be extended by various classes which implements the algorithm. Having instance of interface in Applicationobject would make possible for selecting different algorithms interchangeably.
Based on the File type, we can instantiate the right kind of Compressor. Here we can also have Factory method which helps in deciding the right kind of subclass of IcompressStrategy to instantiate.
Implementation of Strategy pattern in Dynamic Object Oriented language
Ruby Code which makes use of o-o principle to illustrate strategy pattern
class CompressContext def initialize(compression_strategy) self.class.send :include, compression_strategy end end module TextCompressor def compress puts 'Compression the text file' end end module ImageCompressor def compress puts 'Compression the image file' end end class Main def self.compressandSend(*args) file = args[0] #=> compressing text file compressType = CompressContext.new(TextCompressor) compressType.compress #=> compressing image file compressType = CompressContext.new(ImageCompressor) compressType.compress end Main.compressandSend("filepath") end
Here is quick overview of how we are implementing, we are defining concreteStrategy in separate modules TextCompressor and ImageCompressor and appropriate module would be included in context, i.e in CompressContext and appropriate strategy would be used by invoking the method implemented in the module.
Ruby Code which makes use of blocks to illustrate strategy pattern
class CompressContext def initialize(&strategy) @strategy = strategy end def compress @strategy.call end end #=> Compress Text File textCompresser = CompressContext.new { puts 'block which can be used for text compression' } textCompresser.compress #=> Compress Image File imageCompresser = CompressContext.new { puts 'block which can be used for Image compression' } imageCompresser.compress
In the above code, we are making use of closure language feature of Ruby to initialize appropriate strategy in initialize method and invoking the method later.
Implementation of Strategy pattern in Static Object Oriented language
Java Code to demonstrate strategy Pattern implementation
// Main Method of Context Class.. File file = getFile(); //get file path.. Compresser ci = CompresserFactory.getCompresser( file.type() ); ci.performAction(); // implementations: interface Compresser { public void compressAction(); } class ImageCompressStrategy implements Compresser { public void compressAction() { // Use Standard JPEG compress algorithm .... } } class TextCompressStrategy implements Compresser { public void compressAction () { // use Haufman text compress algorithm. } }
Comparison of Dynamic and Static o-o language features in implementing Strategy pattern
The following are the key observations noted when we implemented Strategy inDynamic and Static oo llity anguage:
- For implementing the strategy in static, we need to define common interface and the interface must be extended by
- other class which implements different algorithm.In Case of Dynamic oo as we have seen in the example section 3.2, modules can extended to :include strategy methods.No need to have common interface.
- In Static o-o, to implement each algorithm we need to have different interface/Strategy which would be extended by different :ConcreteStrategy Class.This would result in increasing the code base.Where as in the dynamic oo, each module can have different strategy's :and context class can include module and selectively call the appropriate method.