An Absolute Beginner's Tutorial for Understanding and Implementing the Strategy Pattern in C#
The aim of this article is to understand the basics of the Strategy pattern, explore scenarios where it can be useful, and create a rudimentary implementation for better understanding. This is not intended to demonstrate how to implement the Strategy pattern in real-world applications, and the example used is deliberately simple and far from real-world scenarios. The purpose of this article is purely to illustrate the concept of the Strategy pattern.
Background
There are many scenarios in application development where there are multiple ways to perform the same operation. We want our application to support all these options seamlessly.
For example, consider payment options on e-commerce portals. A user can pay using net banking, a credit card, or PayPal. Each option represents a different way of performing the same operation, with distinct application logic.
Another example is sorting. A sequence can be sorted using various sorting algorithms.
In situations where users need the flexibility to choose among multiple approaches for an operation, the Strategy pattern is a suitable design choice.
The Strategy pattern's philosophy is to provide multiple strategies for executing an operation and allow the user (or an algorithm) to select the appropriate one. The Gang of Four (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."
Class Diagram Components
Using the Code
Let’s create a toy application for converting audio files from WAV to MP3 format. The user will select a source .wav file and choose the quality of the target MP3 file (low, average, or high).
In our code:
Note: This is a dummy application for demonstration purposes. The design choices are solely to illustrate the Strategy pattern and may not be ideal for real-world applications.
Step 1: Define the IWavToMp3ConvertionStrategy Interface
This interface will be implemented by all concrete strategies.
interface IWavToMp3ConvertionStrategy
{
void Convert();
}
Step 2: Implement Concrete Strategies
Here, each strategy defines the logic for a specific quality of conversion.
Recommended by LinkedIn
// 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");
}
}
Step 3: Create the Context Class
The WavToMP3Convertor class represents the Context in the Strategy pattern.
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();
}
}
In this class:
Step 4: Implement the Presentation Layer
The presentation layer allows the user to select the conversion strategy.
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" };
// Emulate the selection of quality
Console.WriteLine("Enter the type of output: \n1. Low Quality\n2. Average Quality\n3. High Quality");
int choice = Console.Read();
// Select the strategy based on the user's choice
if (choice == '1')
{
selectedStrategy = new LowQualityConversionStrategy();
}
else if (choice == '2')
{
selectedStrategy = new AverageQualityConversionStrategy();
}
else if (choice == '3')
{
selectedStrategy = new HighQualityConversionStrategy();
}
// Perform the conversion
if (selectedStrategy != null)
{
WavToMP3Convertor convertor = new WavToMP3Convertor(file);
convertor.Convert(selectedStrategy);
}
}
Note: In real-world applications, concrete strategies are often created using a factory or service locator pattern, not via switch statements.
Comparing with the GoF Class Diagram
In our example:
The Context class (WavToMP3Convertor) remains unaffected by changes to strategies, illustrating the core benefit of the Strategy pattern.
Points of Interest
In this article, we explored the basics of the Strategy pattern and its ability to decouple client code from specific implementations.
Key takeaways:
This article is written from an absolute beginner's perspective to demonstrate the pattern in action. I hope you find it informative!
#CSharpProgramming#DesignPatterns#StrategyPattern#SoftwareDevelopment