Strategy design pattern demystified

By definition from wikipedia, strategy pattern also called as policy pattern is a software design pattern whereby an algorithm behaviour can be selected at runtime. Using the pattern you define a family of algorithms and making them interchangeable.

With strategy pattern the specific behaviors should not be inherited and to avoid this you use interfaces to abstract the behavior with which each of the strategy implementation should implement. And this should be in harmony with the open/closed principle which states that classes should be open to extensibility and closed to modifications.

The pattern is really simple, nice pattern to get started on design patterns and very applicable as implement algorithms on a daily basis.

The purpose for this design pattern includes but not limited to the following:

  •  Encapsulates a family of related algorithms
  •  It allows various algorithm to vary and evolve separately from the context (Context being the class using them)
  •  Allowing a class to maintain a single purpose

Some of the red flag to know that you need to implement this pattern in you code might include:

  • Switch statement in code
  • Adding a new way of implementation of a certain algorithm will include adding a new file for that specific implementation.

In this post we are going to consider, a situation where we are required to calculate both weighted and simple average mean of some given rating e.g could game rating, restaurant rating etc,etc. Just from the requirement you can easily see that we will probably need some different ways of implementing each of them, since hardly can you get one from the other. And this now will prompt to us to use strategy pattern to implement the different algorithms.

Assuming we have the following Review class which will contain a rating property:

public class Review
{
public int Rating { get; set; }
}

For us to be in harmoney with Open/Closed principle, since the two algorithm are involved in computing then we will have an interface with one function, simple as:

internal interface IRatingAlgorithm
{
int Compute(IList<Review> reviews);
}

And therefore any algorithm that needs to be in this family of algorithm, MUST implement this interface. And in case we need to introduce some other algorithms then we will just create a new class that implement the interface, and not modifying the existing ones (Hope now you can see the Open/Closed principle at work). Our first implementation is for simple average mean which uses LINQ average extension function

    internal class SimpleRatingAlgorithm : IRatingAlgorithm
{

public int Compute(IList<Review> reviews)
{
return (int)reviews.Average(r => r.Rating);
}
}

Easy huh? The weighted version go like this:

internal class WeightedRatingAlgorithm : IRatingAlgorithm
{

public int Compute(IList<Review> reviews)
{
var result = default(int);
var counter = 0;
var total = 0;

for (int i = 0; i < reviews.Count(); i++)
{
if (i < reviews.Count() / 2)
{
counter += 2;
total += reviews[i].Rating * 2;
}
else
{
counter += 1;
total += reviews[i].Rating;
}
}

result = total / counter;
return result;
}
}

And our context class is here:

internal class Rater
{
private readonly List<Review> _reviews;

public Rater(List<Review> reviews)
{
_reviews = reviews;
}

public int ComputeResult(IRatingAlgorithm algorithm)
{
return algorithm.Compute(_reviews);
}
}

Our client will now use the context class to call either of our algorithms. And here is how I am doing it, with a small static helper method to build some static review.

class Program
{
static void Main(string[] args)
{
var reviews = SampleReviews(new[] { 4, 8 });

var rater = new Rater(reviews);

var simpleresult = rater.ComputeResult(new SimpleRatingAlgorithm());

var weighted = rater.ComputeResult(new WeightedRatingAlgorithm());

Console.WriteLine("Simle average mean: {0} , Weighted mean {1}", simpleresult, weighted);
Console.ReadLine();
}

public static List<Review> SampleReviews(params  int[] rating)
{
return rating.Select(x => new Review { Rating = x }).ToList();
}
}

Advantages

  • Strategies may not use members of the containing class they will have to be self sustaining
  • Test may now be written for individual concrete strategies
  • Strategies may be mocked when testing the context class
  • Adding a new strategy does not break the Open/closed principle

Happy coding 🙂

 

 

Advertisements

About Piusn

Enthusiastic Software Developer

One response to “Strategy design pattern demystified”

  1. exhibition stand displays says :

    great submit, very informative. I wonder why the opposite experts of this sector don’t
    realize this. You must proceed your writing. I am confident, you have a great readers’ base already!

What's your thought on the subject?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: