You are on page 1of 5

An Absolute Beginner's Tutorial for

Understanding and Implementing Strategy


Pattern in C#
Rahul Rajat Singh, 17 Jan 2016

Introduction
The aim of this article is to understand the basics of the Strategy pattern and try to see when it can
be useful and have a rudimentary implementation for better understanding. This is no way to
implement the strategy pattern in real world applications and the example taken is also far from real.
The idea of this this article is to illustrate the concept of strategy pattern only.

Background
There are many scenarios in application development where there are multiple ways of doing the
same operation. We want our application to have the possibility of using all these ways of
performing the operations. An example could be payment on ecommerce portals, I could choose to
pay using netbanking, I could choose to use a credit card, or I can even choose PayPal for making
the payment. All these are ways of performing the same operations. Though every choice will have to
follow a different application logic, i.e. separate code.

One more example where we could have the same operation in multiple ways is sorting. I could sort
a sequence using any one of the sorting algorithms. So when I have a situation when I want to
develop the application in such a way that for any operation the user could choose one of many
available options, then perhaps that is the right place to incorporate the Strategy pattern.

The philosophy of the Strategy pattern is to have multiple strategies for doing some operation and
let the user choose (or some algorithm based on input data) the appropriate strategy to carry out
the operation. GoF defines the Strategy pattern as “Define a family of algorithms, encapsulate each
one, and make them interchangeable. Strategy lets the algorithm vary independently from clients
that use it.”
Let us try to understand each component of this class diagram.

 Strategy: This is the interface common to all algorithms. Context uses this interface to perform the
operations.
 ConcreteStrategy: This is the class that implements the actual algorithm.
 Context: This is the client application that performs the decision making for which strategy should
be used and uses the Strategy interface (which is referring to a ConcreteStrategy object) to perform
the operations.

Using the code


So to understand these concepts, let us work on a toy application for converting audio files from
Wav to MP3. Here the user will have an option of selecting the source .wav file and then select the
quality of the target MP3 file to be created. The user interface will provide the user with three quality
values for the target file.

In our code what we will do is that we will create multiple strategies each that we will be using are to
define the quality of the output. We are implementing all these separate strategies so that
conversion code will remain unaffected by the code that is specific to dealing with the quality of the
output. The actual code that is doing the conversion will be independent of the implementation
details of these different strategies and will work in the same fashion for any selected strategy or
even when the new strategies are added.

Note: This is not a real conversion application, only a dummy application but perhaps the real
application can be developed on the same lines. Also, the choice of the application and design is
purely to demonstrate the Strategy pattern in action (could be a bad design if we take the holistic
view).

So let us first write the interface IWavToMp3ConvertionStrategy that will be implemented by all
Concrete Strategies.
Hide Copy Code

interface IWavToMp3ConvertionStrategy
{
void Convert();
}

Once we have the interface ready, we can write the Concrete Strategy classes.

Hide Copy Code

//Strategy class for low quality conversion


class LowQualityConversionStrategy : IWavToMp3ConvertionStrategy
{
public void Convert()
{
Console.WriteLine("Low quality conversion performed");
}
}

//Strategy class for average quality conversion


class AverageQualityConversionStrategy : IWavToMp3ConvertionStrategy
{
public void Convert()
{
Console.WriteLine("Average quality conversion performed");
}
}

//Strategy class for high quality conversion


class HighQualityConversionStrategy : IWavToMp3ConvertionStrategy
{
public void Convert()
{
Console.WriteLine("High quality conversion performed");
}
}

We have our concrete classes containing the logic that is different among all strategies. All the logic
that is common to all the conversion feature will be present in the class that will be choosing the
strategy for the actual conversion i.e. the context class in the above diagram. So let us write the
Context class i.e WavToMP3Convertorthat will be using
the IWavToMp3ConvertionStrategy interface to perform the conversion.

Hide Copy Code

public class WavToMP3Convertor


{
AudioFile m_fileData = null;
IWavToMp3ConvertionStrategy m_Convertor = null;

public WavToMP3Convertor(AudioFile fileData)


{
m_fileData = fileData;
}

public void Convert(IWavToMp3ConvertionStrategy convertor)


{
m_Convertor = convertor;
m_Convertor.Convert();
}
}

What is happening in this class is that the presentation layer is passing the actual file data to this
class. then when the conversion will be requested a concrete strategy instance will also be passed to
this class so that this class can use the passed strategy for the conversion.

The important thing to note in this code is that this code will remain unaffected even if we add more
strategies. Also, if we were to create a SDK/DLL, the user will have options to create their own
strategies and simply pass them to this class to use their custom strategies.

Finally we will have our presentation layer which will let the user decide the converstion strategy and
pass the appropriate strategy to the conversion class.

Hide Shrink Copy Code

static void Main(string[] args)


{
IWavToMp3ConvertionStrategy selectedStrategy = null;

Console.WriteLine("Assuming the file for conversion has been selected already");


AudioFile file = new AudioFile { Title = "Sample File" };

// Let us try to emulate the selection of quality here


Console.WriteLine("Enter the type of output \n1. Low Quality\n2. Average Quality\n3.
High Quality");

int choice = Console.Read();

// Now based on the users' choice lets go ahead and select strategy to convert the
file
if (choice == '1')
{
selectedStrategy = new LowQualityConversionStrategy();
}
else if (choice == '2')
{
selectedStrategy = new AverageQualityConversionStrategy();
}
else if (choice == '3')
{
selectedStrategy = new HighQualityConversionStrategy();
}

// Now the code which is doing the conversion. this code beed
// not be changes even if we implement more strategies
if (selectedStrategy != null)
{
WavToMP3Convertor convertor = new WavToMP3Convertor(file);
convertor.Convert(selectedStrategy);
}
}

Note: The selection of strategy is being done in the presentation layer in this sample application.
This is rather a very contrived way of creating the concrete strategies. In real world the concrete
strategies will be created either using a factory or a service locator based on the user's selection on
UI.

Now when we run the application we can see that the file conversion will happen based on the user
selected options and the right strategy will be used. Now let us try to compare our code with the
GoF class diagram.

So we can see that IWavToMp3ConvertionStrategy is our strategy


interface, WavToMP3Convertor is our context class
and LowQualityConversionStrategy , AverageQualityConversionStrategy and HighQuali
tyConversionStrategy are our concrete strategies. The important thing to note is that the
Context class i.e. WavToMP3Convertor will remain unaffected by the concrete strategies and
adding/removing strategies will not have any effect on this class.

Points of interest
In this article we have looked at the basics of strategy pattern and how we can use this pattern to
decouple the client code with the actual implementation. We have used a rather contrived example
just to demonstrate this pattern. The creation of concrete strategy was also not be done using a
switch statement but here the intention was to show how the Context class remain unaffected by the
choice of strategies and thus this simple way of creating concrete strategy. This article has been
written from an absolute beginner's perspective. I hope this has been informative.

You might also like