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.
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 into different formats (like MP3 to WMA). Here the user will have an option of selecting
the source file and then deciding the target output type format. The operation that will be performed is to convert the source file to the target output format.
The multiple strategies that we will be using are to define the quality of the output. The user could choose to convert to a low quality output (perhaps because it is fast
and is of small size). The user could choose to convert to a high quality output (perhaps because he wants to use it on high-end audio products from BOSE or B&O),
or he could just choose an average quality output (perhaps to put it on his cell phone). We implement all these as separate strategies so that the client
code can be independent of the implementation details of these different strategies and will work in the same fashion for any selected strategy.
Note: There is no real 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 Strategy that will be implemented by all ConcreteStrategys.
interface IStrategy
{
void Convert();
}
And here is the C++ Implementation of Strategy
class IStrategy
{
public:
virtual void Convert() = 0;
};
Once we have the interface ready, we can write the ConcreteStrategy classes.
class LowQualityConversion : IStrategy
{
const int QUALITY_VALUE = 50;
#region IStrategy Members
public void Convert()
{
FileConvertor convertor = new FileConvertor(QUALITY_VALUE);
convertor.ConvertFile();
}
#endregion
}
class AverageQualityConversion :IStrategy
{
const int QUALITY_VALUE = 150;
#region IStrategy Members
public void Convert()
{
FileConvertor convertor = new FileConvertor(QUALITY_VALUE);
convertor.ConvertFile();
}
#endregion
}
class HighQualityConversion : IStrategy
{
const int QUALITY_VALUE = 250;
#region IStrategy Members
public void Convert()
{
FileConvertor convertor = new FileConvertor(QUALITY_VALUE);
convertor.ConvertFile();
}
#endregion
}
Now Let us see the C++ implementation of ConcreteStrategy
class LowQualityConversion : public IStrategy
{
const int QUALITY_VALUE;
public:
LowQualityConversion()
: QUALITY_VALUE(50)
{
}
void Convert()
{
FileConvertor convertor(QUALITY_VALUE);
convertor.ConvertFile();
}
};
class AverageQualityConversion : public IStrategy
{
const int QUALITY_VALUE;
public:
AverageQualityConversion()
: QUALITY_VALUE(150)
{
}
void Convert()
{
FileConvertor convertor(QUALITY_VALUE);
convertor.ConvertFile();
}
};
class HighQualityConversion : public IStrategy
{
const int QUALITY_VALUE ;
public:
HighQualityConversion()
: QUALITY_VALUE(250)
{
}
void Convert()
{
FileConvertor convertor(QUALITY_VALUE);
convertor.ConvertFile();
}
};
We have our concrete classes using another class for doing the actual conversion. This is to demonstrate that the concrete strategy classes should only contain
the logic that is different among all strategies and having multiple strategies does not mean that we can have duplication of code.
Note: If we would be writing the Sort example, we will not be needing any helper class since all the sort
algorithms and different logic could be simply implemented inside the concrete strategy classes without any code duplication.
Let us see what this class is doing:
class FileConvertor
{
int qualityParameter;
public FileConvertor(int qualityParam)
{
qualityParameter = qualityParam;
}
public void ConvertFile()
{
if (qualityParameter < 100)
{
Console.WriteLine("Converting the file in LOW quality");
}
else if (qualityParameter > 100 && qualityParameter < 200)
{
Console.WriteLine("Converting the file in MEDIUM quality");
}
else
{
Console.WriteLine("Converting the file in HIGH quality");
}
}
}
Let us look at the C++ Implementation of this class too
class FileConvertor
{
int qualityParam_;
public:
FileConvertor(int qualityParam)
: qualityParam_(qualityParam)
{
}
void ConvertFile()
{
if (qualityParam_ < 100)
{
std::cout << "Converting the file in LOW quality";
}
else if (qualityParam_ > 100 && qualityParam_ < 200)
{
std::cout << "Converting the file in MEDIUM quality";
}
else
{
std::cout << "Converting the file in HIGH quality";
}
}
};
and finally let us write the Context class that will be using the IStrategy interface and will have the decision making logic to use the actual strategy.
static void Main(string[] args)
{
IStrategy selectedStrategy = null;
Console.WriteLine("Assuming the file for conversion has been selected already");
Console.WriteLine("Enter the type of output \n1. Low Quality\n2. Average Quality\n3. High Quality");
int choice = Console.Read();
if (choice == '1')
{
selectedStrategy = new LowQualityConversion();
}
else if (choice == '2')
{
selectedStrategy = new AverageQualityConversion();
}
else if (choice == '3')
{
selectedStrategy = new HighQualityConversion();
}
if (selectedStrategy != null)
{
selectedStrategy.Convert();
}
}
and the C++ Implementation for the Context is
int _tmain(int argc, _TCHAR* argv[])
{
IStrategy *selectedStrategy = 0;
cout << "Assuming the file for conversion has been selected already";
cout << "Enter the type of output \n1. Low Quality\n2. Average Quality\n3. High Quality";
int choice;
cin >> choice;
if (choice == 1)
{
selectedStrategy = new LowQualityConversion();
}
else if (choice == 2)
{
selectedStrategy = new AverageQualityConversion();
}
else if (choice == 3)
{
selectedStrategy = new HighQualityConversion();
}
if (selectedStrategy != 0)
{
selectedStrategy->Convert();
delete selectedStrategy;
}
return 0;
};
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.

Points of interest
This pattern can sometimes be used to have a "plug and play" type of architecture where we can have various strategies plugged in to perform any operation
without affecting the client code.
History
- 14 March 2012: First version.
- 20 March 2012: Added the C++ Implementation for Strategy Pattern.