Strategy Design Pattern in C#

Strategy Design Pattern in C# with Examples

In this article, I will discuss the Strategy Design Pattern in C# with Examples. Please read our previous article discussing the Visitor Design Pattern in C# with Examples. The Strategy Design Pattern falls under the category of Behavioral Design Pattern. As part of this article, we will discuss the following pointers in detail.

  1. What is the Strategy Design Pattern?
  2. Understanding the Strategy Design Pattern with Real-Time Examples.
  3. Implementing the Strategy Design Pattern in C#.
  4. Understanding the Class or UML Diagram of the Strategy Design Pattern.
  5. Advantages of Strategy Design Pattern in C#.
  6. When to use the Strategy Design Pattern?
What is the Strategy Design Pattern?

According to the Gang of Four Definitions, define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

The Strategy Design Pattern is a Behavioral Design Pattern that enables selecting an algorithm’s behavior at runtime. Instead of implementing a single algorithm directly, run-time instructions specify which of a family of algorithms to use. This pattern is ideal when you need to switch between different algorithms or actions in an object dynamically. That means the Strategy Design Pattern is used when we have multiple algorithms (solutions) for a specific task, and the client decides which algorithm to use at runtime. 

Example to Understand Strategy Design Pattern

To understand the above explanation better, please look at the following image. As shown in the below diagram, we have one task, and to solve the task, we have three solutions (i.e., Solution 1, Solution 2, and Solution 3). That means using the above three solutions, we can achieve the task. As per the Strategy Design Pattern, the client will decide which solution should be used only at runtime. So, the client will decide whether to use Solution 1 to achieve the task, Solution 2 to achieve the task, or Solution 3 to achieve the task only at run time.

What is the Strategy Design Pattern in C#?

Understanding the Strategy Design Pattern with Real-time Example:

Let us understand the Strategy Design Pattern in C# using one real-time example. Please have a look at the following image. As you can see, in my D drive, I have a folder called DotNetDesignPattern; within that folder, multiple text files are there. My business requirement is to compress this DotNetDesignPattern folder and send the compressed file to the client.

For this requirement, I have two solutions. The first solution is to compress the folder into RAR format and send it to the client; the second is to compress the folder into ZIP format and send it to the client. So, for the above requirement, I have two solutions shown in the image below.

Strategy Design Pattern with Real-time Example in C#

As per the Strategy Design Pattern, multiple solutions exist for a Particular Problem (Task). The client will decide which solution to use only at runtime, not compilation time. So, in our example, the client will decide at runtime in which format he wants the file.

How to Implement the Strategy Design Pattern in C#?

The Strategy Pattern defines a set of algorithms, encapsulates each algorithm, and makes them interchangeable. It lets the algorithm vary independently from clients that use it. Let’s break down the implementation of the Strategy Pattern in C#:

  • Strategy (Interface or Abstract Class): This defines an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy.
  • ConcreteStrategy: This implements the algorithm using the Strategy interface.
  • Context: This maintains a reference to a Strategy object and may define an interface that lets Strategy access its data.

Let us discuss the step-by-step procedure to implement the above example using the Strategy Design Pattern in C#. Once we implement the example, we will understand the UML Diagram of the Strategy Design Pattern by comparing it with our example so that you can easily understand the different components (classes and interfaces) involved in the Strategy Design Pattern.

Step 1: Creating Strategy Interface

Create an interface named ICompression.cs and then copy and paste the following code. The Strategy Interface declares the methods common to all supported algorithm versions. The Context object will use this Strategy Interface to call the algorithm defined by the Concrete Strategies.

namespace StrategyDesignPattern
{
    // Strategy Interface
    // The Strategy Interface declare methods that are common to all supported versions of the algorithm.
    // The Context Object is going to use this Strategy Interface to call the algorithm defined by Concrete Strategies.
    public interface ICompression
    {
        void CompressFolder(string compressedArchiveFileName);
    }
}
Step 2: Creating Concrete Strategies

The Concrete Strategies are the classes that implement the Strategy interface. Each Concrete Strategy by which we will compress a file item must implement the method CompressFolder of the ICompression interface. Let’s create two Concrete Strategy classes as per our business requirement.

RarCompression:

Create a class file named RarCompression.cs and copy and paste the following code. The following RarCompression Concrete Strategy implements the Strategy Interface and Implement the CompressFolder Method. This algorithm returns the Folder in RAR format.

using System;
namespace StrategyDesignPattern
{
    // Concrete Strategy A
    // The following RarCompression Concrete Strategy implement the Strategy Interface and 
    // Implement the CompressFolder Method. 
    public class RarCompression : ICompression
    {
        public void CompressFolder(string compressedArchiveFileName)
        {
            Console.WriteLine("Folder is compressed using Rar approach: '" + compressedArchiveFileName
                 + ".rar' file is created");
        }
    }
}
ZipCompression:

Create a class file named ZipCompression.cs and copy and paste the following code. The following ZipCompression Concrete Strategy implements the Strategy Interface and Implement the CompressFolder Method. This algorithm returns the Folder in ZIP format.

using System;
namespace StrategyDesignPattern
{
    // Concrete Strategy B
    // The following ZipCompression Concrete Strategy implement the Strategy Interface and 
    // Implement the CompressFolder Method. 
    public class ZipCompression : ICompression
    {
        public void CompressFolder(string compressedArchiveFileName)
        {
            Console.WriteLine("Folder is compressed using zip approach: '" + compressedArchiveFileName
                 + ".zip' file is created");
        }
    }
}
Step 3: Creating Context

Create a class file, CompressionContext.cs, and copy and paste the following code. This context class contains a property that holds the reference of a Concrete Strategy object. The client will set this property at run-time according to the required algorithm. 

namespace StrategyDesignPattern
{
    // The Context Provides the interface which is going to be used by the Client.
    public class CompressionContext
    {
        // The Context has a reference to one of the Strategy objects. 
        // The Context does not know the concrete class of a strategy. 
        // It should work with all strategies via the Strategy interface.
        private ICompression Compression;

        //Initializing the Strategy Object i.e. Compression using Constructor
        public CompressionContext(ICompression Compression)
        {
            // The Context accepts a strategy through the constructor, 
            // but also provides a setter method to change the strategy at runtime
            this.Compression = Compression;
        }

        //The Context allows replacing a Strategy object at runtime.
        public void SetStrategy(ICompression Compression)
        {
            this.Compression = Compression;
        }

        // The Context delegates the work to the Strategy object instead of
        // implementing multiple versions of the algorithm on its own.
        public void CreateArchive(string compressedArchiveFileName)
        {
            //The CompressFolder method is going to be invoked based on the strategy object
            Compression.CompressFolder(compressedArchiveFileName);
        }
    }
}
Step 4: Client

The Main method of the Program class is going to be the client. So, modify the Main method of the Program class as shown below. 

using System;
namespace StrategyDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            // The client code picks a concrete strategy and passes it to the context. 
            // The client should be aware of the differences between strategies in order to make the right choice.

            //Create an instance of ZipCompression Strategy
            ICompression strategy = new ZipCompression();

            //Pass ZipCompression Strategy as an argument to the CompressionContext constructor
            CompressionContext ctx = new CompressionContext(strategy);
            ctx.CreateArchive("DotNetDesignPattern");

            //Changing the Strategy using SetStrategy Method
            ctx.SetStrategy(new RarCompression());
            ctx.CreateArchive("DotNetDesignPattern");

            Console.Read();
        }
    }
}
Output:

How to implement the Strategy Design Pattern in C#?

Use Cases of Strategy Design Pattern:
  • When you have many classes that differ only in their behavior, strategies provide a way to configure a class with one of many behaviors.
  • When you need to switch algorithms used within an object at runtime dynamically.
  • When you have a lot of conditional statements in different places to execute various behaviors of the same algorithm.
Strategy Design Pattern UML or Class Diagram:

Let us understand the Class Diagram or UML Diagram of the Strategy Design Pattern and the different components involved by comparing the UML Diagram with our Example. Please have a look at the following image.

Strategy Design Pattern UML or Class Diagram

As shown in the above diagram, three participants are involved in the Strategy Design Pattern in C#. Their role and responsibilities are as follows:

  1. Strategy: The Strategy declares an interface that all supported algorithms will implement. Here, algorithms mean methods that the concrete strategy classes will implement. In our example, it is the CompressFolder method of the ICompression interface.
  2. ConcreteStrategy: These will be concrete classes, and they must implement the Strategy (ICompression) interface and provide implementations for the algorithm, i.e., implementing the interface methods. In our example, it is the RarCompression and ZipCompression classes.
  3. Context: This class will maintain a reference to a Strategy object and then use that reference to call the algorithm defined by a particular ConcreteStrategy (i.e., either RarCompression or ZipCompression). In our example, it is the CompressionContext class.
Advantages of Strategy Design Pattern:
  • Flexibility: Allows dynamically changing the behavior of an object.
  • Loose Coupling: The strategy classes are independent of each other and the context class, promoting loose coupling.
  • Reuse: Strategies can be reused across different contexts.
  • Isolation: Each strategy can be implemented and maintained independently from the others.
  • Open/Closed Principle: New strategies can be introduced without changing the context.
When to Use Strategy Design Pattern in C#?

The Strategy Design Pattern in C# is particularly useful in scenarios where:

  • Dynamic Behavior Change: When you need to dynamically change the behavior of an object based on some context or state. This allows the algorithm to be selected at runtime rather than being statically defined.
  • Encapsulating Algorithms: If you have several different algorithms or behaviors for a specific task, and you want to encapsulate each one in its own class. The Strategy pattern allows you to switch between these algorithms without changing the clients that use them.
  • Avoiding Conditional Statements: In situations where you might otherwise use multiple conditional statements (like if/else or switch/case) to select desired behaviors. The Strategy pattern helps to avoid this conditional complexity.
  • Support for Open/Closed Principle: If you anticipate that new algorithms or behaviors will be added in the future, the Strategy pattern allows for extending the capabilities without modifying the existing code, thus supporting the Open/Closed Principle.
  • Isolating the Implementation Details: When you want to isolate the implementation details of an algorithm from the code that uses it. This can help in making the code easier to maintain and understand.
  • Unit Testing and Mocking: The pattern makes it easier to unit test the different behaviors of a class independently, as well as to mock out these behaviors if needed.
  • Implementing Different Business Rules: If different clients or systems require different business rules or algorithms, the Strategy pattern allows for configuring a class with one of many behaviors based on the client’s needs.

In the next article, I will discuss Real-Time Examples of Strategy Design Patterns in C#. Here, in this article, I try to explain the Strategy Design Pattern in C# with Examples. I hope you understand the need and use of the Strategy Design Pattern in C#.

6 thoughts on “Strategy Design Pattern in C#”

  1. Hello,

    the example is good!

    i have a question

    what is the use of these lines?

    public void SetStrategy(ICompression Compression)
    {
    this.Compression = Compression;
    }

    Im debuggin but never go through these lines

    Thanks

  2. Hey,

    Its assigning the inherited instance of class which strategy you wanted to set to the current context.

    As you can see in the sample, context initially starts with `ZipCompression()` strategy and then SetStrategy() method called for changing strategy as `RarCompression()`.

  3. Hello,

    the example is good!

    i have a question

    why CompressionContext class is required, without this class also we can access CompressFolder from Client using interface.

    i did not understand, can you clearly explain,

    waiting for your reply.

    thanks

      1. Yes context class is required. I think detailed way could be to let client not know which concrete class has to be called. Rather just let client specify text ‘rar’ or ‘zip’ at runtime and based on that the context should initialize respective concrete class based on some switch. And then use create archive as explained in the article.

Leave a Reply

Your email address will not be published. Required fields are marked *