The Strategy Pattern — Design Patterns

Mahmut Kasimoglu
4 min readDec 23, 2023

--

Generated using Gpt-4

The Strategy Pattern is one of the Behavioral Design Patterns that exist, It is a powerful and relatively simple design pattern to understand and implement.

The idea behind the pattern is to isolate the parts of a system that vary by introducing a family of algorithms/strategies that can be dynamically changed during runtime. Leveraging the concept of composition and conforming to the “O” from SOLID Principles, namely the “Open and Closed Principle” which states that classes and methods should be open for extension but closed for modification.

Now enough with the jargon! and let's get started by taking a look at real-world applications of this pattern, that way we can understand more clearly the things I mentioned above. I will be demonstrating this in C#.

Problem

I am going to use a realistic scenario in contrast to hypothetical ones so that we can better understand how this pattern could be applied in the real world.

So, let's take a scenario where your boss asks you to build a Compression Algorithm, and at first you are required to build an algorithm for compressing files into Zip files, however, your boss lets you know that the company will require more strategies in the foreseeable future as the client’s need evolves.

So as a good developer, your job is to build a future-proof feature that is flexible and adaptable to change, You search for the perfect way to achieve this and that’s when you find out about the Strategy Pattern!

Solution

Below is an example of how you can use the Strategy Pattern to approach the scenario above.

public class FileCompressor { 

private ICompressionStrategy _compressionStrategy;

// abstract strategy that we can switch from during run time
// this is where we leverage Composition, By composing a class with
// the desired strategy(s), Both during compile time and during run time!
public FileCompressor(ICompressionStrategy compressionStrategy)
_compressionStrategy = compressionStrategy;
}

// This is where the "Isolate parts of applications that vary"
// and the "Open Closed Principle" comes in!
// We could want to Compress files using a Zip or A Rar algorithm .etc
// So instead of coming to this method in the future
// and adding an If or switch statements to handle this,
// we Isolate/Encapsulate the implementation and let the client decide
// what strategy to use.
public void Compress(File file) {
_compressionStrategy.Compress(file);
}

// this is how we can change the compression strategy during run time.
public void SetStrategy(ICompressionStrategy compressionStrategy) {
_compressionStrategy = compressingStrategy;
}
}

public interface ICompressionStrategy {
void Compress(File file)
}

public class ZipCompressionStrategy : ICompressionStrategy {
void Compress(File file) => {
// Zip Compression Strategy
}
}

// Usage Of the pattern

File file; //lets assume that we are getting this from a Controller's Action

var zipFileCompressor = new FileCompressor(new ZipCompressionStrategy());

// compression of the file using the zip algorithm.
zipFileCompressor.Compress(file);


// now lets say that your boss asks you to create a Rar algorithm
// you will just have to create the new strategy with its corresponding algorithm
// adhering to the Open Closed Principle but Extending the class and not modifying it.

public class RarCompressionStrategy : ICompressionStrategy {
void Compress(File file) => {
// Rar Compression Strategy
}
}


var rarFileCompressor = new FileCompressor(new RarCompressionStrategy());

rarFileCompressor.Compress(file); // voila, its that simple!

// note - we can use the Factory Pattern in Conjunction with
// the Strategy pattern to decide the composition of the FileCompressor class
// depending on the outcome we want to achieve.

now let us understand the above further, What we have done is created a context class which in this case is the FileCompressor, Its context is to compress files. We have also created a strategy interface called ICompressionStrategy which makes the Strategy Pattern possible. We let the client inject the concrete implementation of this interface into the FileCompressor class to decide which compression strategy to use. this way we have a completely dynamic and flexible structure that allows us to extend the functionality of FileCompressor as much as we would like without causing any problems down the road.

Note — The power of the strategy pattern truly shines when we have classes with more than just one strategy/behavior and when there are multiple variations of those classes.

Conclusion

In conclusion, the strategy pattern is a perfect fit for scenarios where there are behaviors that are prone to frequent changes, especially in classes that are mostly similar but execute just some behaviors differently, the value of this pattern increases as the number of varying classes and functions increases.

I hope you found this article useful and enjoyable. This was my first attempt, and I’m eager to enhance my skills. I would greatly appreciate your feedback, especially constructive criticism, as it will help me grow and improve. Thank you for your support!

--

--