Thursday, February 16, 2012

Design Pattern : Strategy pattern Implementation

The Strategy design pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Intent:

The intent of the Strategy design pattern helps us to divide an algorithm from a host class and then move it to another class. By doing so the client can choose which algorithm will be performed in runtime from a set of algorithms that were implemented earlier.

Motivation & Applicability:

There are common situations when classes differ only in their behaviour. For this case, it is a good idea to isolate the algorithms in separate classes in order to have the ability to select different algorithms at runtime. The Strategy pattern allows us to provide an alternative to subclassing the Context class to get a variety of algorithms or behaviours, eliminates large conditional statements and provides a choice of implementations for the same behaviour.
Use the Strategy pattern whenever:
  • Many related classes differ only in their behaviour
  • You need different variants of an algorithm
  • An algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures.
  • A class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class.

    The classes and/or objects participating in this pattern are:
     
  • Strategy (CalculateStrategy using ICalculateInterface) - declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy
  • ConcreteStrategy (Minus, Plus ) - implements the algorithm using the Strategy interface
  • Context (CalculateClient) - is configured with a ConcreteStrategy object; maintains a reference to a Strategy object and may define an interface that lets Strategy access it's data.

UML

strategy.gif

C# Code Snippet
/* Select the strategy and execute
Here the strategies are Minus and Plus
*/
   class MainApp{
    static void Main()
    {
        CalculateClient minusClient = new CalculateClient(new Minus());
        Response.Write(
"Minus: " + minusClient.Calculate(7, 1).ToString());

         
CalculateClient plusClient = new CalculateClient(new Plus());
         Response.Write(
"Plus: " + plusClient.Calculate(7, 1).ToString());
         // Wait for user        Console.ReadKey();
    }
}
//The interface for the strategies
 
public interface ICalculateInterface {        //define method
   
int Calculate(int value1, int value2);
 }
//The 'ConcreteAggregate' classes
//Strategy 1: Minus
class Minus : ICalculateInterface
{
       
public int Calculate(int value1, int value2)
        {
           
//define logic
           
return value1 - value2;
        }
}
//Strategy 2: Plus
class Plus : ICalculateInterface
{
       
public int Calculate(int value1, int value2)
        {
           
//define logic
           
return value1 + value2;
        }
}
//The client
class CalculateClient
{
       
private ICalculateInterface calculateInterface;

       
//Constructor: assigns strategy to interface
       
public CalculateClient(ICalculateInterface strategy)
        {
            calculateInterface = strategy;
        }

       
//Executes the strategy
       
public int Calculate(int value1, int value2)
        {
           
return calculateInterface.Calculate(value1, value2);
        }
/*Output :Minus: 6
Plus: 8
*/

Another example:
Definition

The Strategy pattern involves separating an algorithm from its host class and putting it in a separate class. When there are multiple strategies available for an algorithm, for a given problem it is always better to separate them in to different objects. If the algorithms are all kept in the one class, the class will be become a big messy conditional statements.

The Strategy pattern enables a client to choose which algorithm to use from a family of algorithms and gives it a simple way to access it.

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.

Note:
  1. Strategy is like Template Method except the Strategy patter consists of details whereas template provides a skeleton for the algorithm.
  2. State is like Strategy except in its objective.
  3. Strategy lets us change the internal object. Decorator lets us change the covering, underlying object remains same.

Design
Let us say that we are implementing text hashing for the system. During the requirements definition the decision is to implement the MD5 hashing; during development SHA1 is added for another requirement, and it kept continuing. Finally the decision is to implement with a couple of options and based on the client strategy it can be changed.

UML Diagram

image2.gif

Code
    public abstract class HashingStrategy    {
        public abstract void HashingInterface(string text);
    }

    public class MD5Hashing : HashingStrategy    {
        public override void HashingInterface(string text)
        {
            MD5 md5 = new MD5CryptoServiceProvider();

            Byte[] bytes;
            bytes = ASCIIEncoding.Default.GetBytes(text);
            Byte[] encodedBytes;
            encodedBytes = md5.ComputeHash(bytes);
            string A = BitConverter.ToString(encodedBytes);
        }
    }
    public class HashingContext
    {
        private HashingStrategy _hashingStrategy;
        public HashingContext(HashingStrategy hashingStrategy)
        {
            _hashingStrategy = hashingStrategy;
        }
        public void HashPassword(string text)
        {
            _hashingStrategy.HashingInterface(text);
        }
    }
    public class SHA1Hashing : HashingStrategy    {
        public override void HashingInterface(string text)
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            Byte[] bytes;
            bytes = ASCIIEncoding.Default.GetBytes(text);
            Byte[] encodedBytes;
            encodedBytes = sha1.ComputeHash(bytes);
            string A = BitConverter.ToString(encodedBytes);
        }
    }
    public class SHA256Hashing : HashingStrategy    {
        public override void HashingInterface(string text)
        {
            SHA256 sha256 = new SHA256CryptoServiceProvider();
            Byte[] bytes;
            bytes = ASCIIEncoding.Default.GetBytes(text);
            Byte[] encodedBytes;
            encodedBytes = sha256.ComputeHash(bytes);
            string A = BitConverter.ToString(encodedBytes);
        }
    }
    public class SHA384Hashing : HashingStrategy    {
        public override void HashingInterface(string text)
        {
            SHA384 sha384 = new SHA384CryptoServiceProvider();
            Byte[] bytes;
            bytes = ASCIIEncoding.Default.GetBytes(text);
            Byte[] encodedBytes;
            encodedBytes = sha384.ComputeHash(bytes);
            string A = BitConverter.ToString(encodedBytes);
        }
    }
Client

HashingContext context;

context = new HashingContext(new SHA1Hashing());
context.HashPassword("Chinna Sushma");

context = new HashingContext(new SHA384Hashing());
h.HashPassword("Chinna Lohetha");

Another example:
Strategy pattern are algorithms inside a class which can be interchanged depending on the class used. This pattern is useful when you want to decide on runtime which algorithm to be used.

Let’s try to see an example of how strategy pattern works practically. Let’s take an example of a math’s calculation where we have strategies like add and substract. Figure ‘Strategy in action’ shows the same in a pictorial format. It takes two numbers and the depending on the strategy it gives out results. So if it’s an addition strategy it will add the numbers, if it’s a substraction strategy it will give the substracted results. These strategies are nothing but algorithms. Strategy pattern are nothing but encapsulation of algorithms inside classes.
Figure: - Strategy in action

So the first thing we need to look in to is how these algorithms can be encapsulated inside the classes. Below figure ‘Algorithm encapsulated’ shows how the ‘add’ is encapsulated in the ‘clsAddStatergy’ class and ‘substract’ in the ‘clsSubstractStatergy’ class. Both these classes inherit from ‘clsStratergy’ defining a ‘calculate’ method for its child classes.
Figure: - Algorithms encapsulated

Now we define a wrapper class called as ‘clsMaths’ which has a reference to the ‘clsStatergy’ class. This class has a ‘setStatergy’ method which sets the strategy to be used.
Figure: - Strategy and the wrapper class

Below figure ‘Strategy client code’ shows how the wrapper class is used and the strategy object is set on runtime using the ‘setStatergy’ method.
Figure: - Strategy client code


Reference:

No comments:

Post a Comment