A strategy design pattern is the most commonly used design pattern in computer programming.
In this post, we’ll start with a basic switch case statement and then we’ll modify the code into strategy design pattern.
A strategy design pattern is one of the behavioral design patterns which will route to a specific algorithm based on the input.
Here’s the definition of strategy design pattern from Wikipedia
In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.
here’s another from dofactory.com
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
When we have a method that behaves differently based on the different inputs supplied then we can make use of the strategy design pattern.
In particular, if we have different business rules for different operations then we can use this strategy design pattern to have different logic for each of the operation (s).
So, if you see too many if/else blocks in a method and they vary differently based on different rules or when we have a switch case that is growing with the feature requests then we can apply the strategy design pattern.
For this article, we’ll assume that if a person walks into the room, he needs to get cool air from any source (Fan, Cooler or A.C.). It is up to the person to turn on what he needs of the day. After turning on any of those available sources we will also output what turned on.
When the user requests for an appropriate cooling strategy we’ll just output which option user has opted for.
We can do this with a switch-case statement.
public static void PrintSelectedCoolingSystem(int collingType) { switch (collingType) { case (int)CoolingSystem.Fan: Console.Write("Fan is turned on!"); break; case (int)CoolingSystem.Cooler: Console.Write("Cooler is turned on!"); break; case (int)CoolingSystem.AC: Console.Write("A.C. is turned on!"); break; default: break; } }
This is basic with hard-coded text that just prints what turned on based on passed input.
Let’s modify the above code by creating different classes for each of these cooling systems. First up, here’s the cooling system interface.
public interface ICoolingSystem { void Print(); }
And here are the concrete class implementations for ICoolingSystem
interface.
public class Fan : ICoolingSystem { public void Print() { Console.Write("Fan is turned on!"); } } public class Cooler : ICoolingSystem { public void Print() { Console.Write("Cooler is turned on!"); } } public class AC : ICoolingSystem { public void Print() { Console.Write("A.C. is turned on!"); } }
With these concrete classes created let’s modify our PrintSelectedCoolingSystem
method.
public static void PrintSelectedCoolingSystem(int collingType) { ICoolingSystem coolingStrategy = null; switch (collingType) { case (int)CoolingSystem.Fan: coolingStrategy = new Fan(); break; case (int)CoolingSystem.Cooler: coolingStrategy = new Cooler(); break; case (int)CoolingSystem.AC: coolingStrategy = new AC(); break; } coolingStrategy?.Print(); }
We’ve changed our case statements by having the instances of the cooling strategies. And finally, we’ll call the Print()
method of the cooling strategy interface to print out the result for us.
With this refactoring done we are already halfway through the strategy pattern. These classes(Fan, Cooler, AC) are our concrete implementations of the Strategy interface.
The context class in the strategy pattern is to call a particular algorithm defined by the concrete strategies. Let’s call our context class as CoolingContext
.
{ private ICoolingSystem _coolingSystem; /// <summary> /// Set appropriate cooling strategy /// </summary> /// <param name="coolingSystem"></param> public void SetCoolingStrategy(ICoolingSystem coolingSystem) { _coolingSystem = coolingSystem; } /// <summary> /// Prints the strategy set /// </summary> public void Print() { _coolingSystem?.Print(); } }
And here’s the PrintSelectedCoolingSystem()
method again with the strategy pattern.
public static void PrintSelectedCoolingSystem(int collingType) { CoolingContext collingContext = new CoolingContext(); switch (collingType) { case (int)CoolingSystem.Fan: collingContext.SetCoolingStrategy(new Fan()); break; case (int)CoolingSystem.Cooler: collingContext.SetCoolingStrategy(new Cooler()); break; case (int)CoolingSystem.AC: collingContext.SetCoolingStrategy(new AC()); break; } collingContext.Print(); }
We must set the strategy first by using the SetCoolingStrategy()
method so that the appropriate concrete strategy is set within the context class and we can call the Print()
method to print the strategy we chose.
That’s it! This is the strategy design pattern.
Here’s the complete source code of strategy design pattern.
namespace StrategyDesignPattern { //The strategy interface public interface ICoolingSystem { void Print(); } //concrete implementation for Fan public class Fan : ICoolingSystem { public void Print() { Console.Write("Fan is turned on!"); } } //concrete implementation for Cooler public class Cooler : ICoolingSystem { public void Print() { Console.Write("Cooler is turned on!"); } } //concrete implementation for A.C. public class AC : ICoolingSystem { public void Print() { Console.Write("A.C. is turned on!"); } } //Context class public class CoolingContext { private ICoolingSystem _coolingSystem; /// <summary> /// Set appropriate cooling strategy /// </summary> /// <param name="coolingSystem"></param> public void SetCoolingStrategy(ICoolingSystem coolingSystem) { _coolingSystem = coolingSystem; } /// <summary> /// Prints the strategy set /// </summary> public void Print() { _coolingSystem?.Print(); } } public enum CoolingSystem { Fan = 1, AC, Cooler } //main method static void Main(string[] args) { Console.WriteLine("Please select a colling system:"); int input = int.Parse(Console.ReadKey().KeyChar.ToString()); Console.WriteLine(); PrintSelectedCoolingSystem(input); } public static void PrintSelectedCoolingSystem(int collingType) { CoolingContext collingContext = new CoolingContext(); switch (collingType) { case (int)CoolingSystem.Fan: collingContext.SetCoolingStrategy(new Fan()); break; case (int)CoolingSystem.Cooler: collingContext.SetCoolingStrategy(new Cooler()); break; case (int)CoolingSystem.AC: collingContext.SetCoolingStrategy(new AC()); break; } collingContext.Print(); } }
In this post, we took a switch case statement and refactored into the strategy design pattern.
SetStrategy
method that will take the Strategy type.SetStrategy()
method and call the Print()
method on the context object, which will then invoke concrete class print method.Karthik is a passionate Full Stack developer working primarily on .NET Core, microservices, distributed systems, VUE and JavaScript. He also loves NBA basketball so you might find some NBA examples in his posts and he owns this blog.
In this post, we’ll see how to test gRPC Server applications using different clients. And… Read More
In this post, we'll create a new gRPC project in ASP.NET Core and see what's… Read More
In this blog post, we’ll see how to run dotnet core projects without opening visual… Read More
Programmatically evaluating policies is useful when we want to provide access or hide some data… Read More
We saw how we could set up policy-based authorization in our previous article. In this… Read More
What is policy-based authorization and how to set up policy-based authorization with handlers and policies… Read More
This website uses cookies.