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. When do we need to use the Strategy Design Pattern in real-time applications?
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 defines a family of algorithms, encapsulates each one, and makes them interchangeable. It allows the algorithm to vary independently from clients that use it.

The Strategy Design Pattern is used when we have multiple algorithms (solutions) for a specific task, and the client decides on the actual implementation for runtime. In simple words, we can say that the Strategy Design Pattern (also called Policy Pattern) attempts to solve the issue where you must provide multiple solutions for the same problem to select one at runtime.

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 with the name ICompression.cs and then copy and paste the following code into it. 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. The following class code is self-explained, so please go through the comment lines for a better understanding.

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. The following Client Code is self-explained, so please go through the comment lines for a better understanding.

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#?

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.
When to use the Strategy Design Pattern in Real-Time Applications?

The Strategy Design Pattern is useful in various real-time scenarios. Consider using the Strategy Pattern when:

  • Multiple Variants of an Algorithm are Available: If there are different ways to perform an operation and you might need to switch between them dynamically, the Strategy Pattern is a good fit. For instance, if you have various sorting algorithms, you can encapsulate each one as a strategy.
  • Algorithm Specific Data: Sometimes, certain algorithms might need data that others don’t. Encapsulating this data inside the concrete strategy can help provide a cleaner interface.
  • Decoupling Algorithm from Client: If you want to decouple the specifics of the algorithm from the class that uses it, thereby making the client class unaware of the algorithm’s specifics, the Strategy Pattern can be employed.
  • Dynamic Strategy Selection: If the application needs to choose among several algorithms dynamically, Strategy Pattern provides a cleaner way to switch at runtime.
  • Extension Over Modification: If you anticipate introducing new algorithms or behaviors without modifying existing code (in adherence with the Open/Closed Principle), the Strategy Pattern is beneficial.
  • Unit Testing: The Strategy Pattern can make unit testing easier by isolating the algorithm from the client class. You can then write unit tests for each strategy independently.

Real-time applications/examples:

  • Compression Algorithms: Suppose you are building a file archiver like ZIP. Users might want to choose between multiple compression algorithms, like LZ77, Huffman, or RLE. The Strategy Pattern can help encapsulate each compression algorithm and allow easy switching.
  • Payment Strategies: In e-commerce systems, there are multiple payment methods – Credit card, PayPal, direct bank transfer, etc. Each payment method can be a separate strategy.
  • Rendering Algorithms: Different rendering algorithms might be suitable for different situations in graphics. For example, a graphics program might offer different algorithms for anti-aliasing.
  • Travel Route Planning: Consider a navigation application where users can choose the route they want: fastest route, shortest route, or scenic route. Each routing algorithm can be implemented as a strategy.
  • Validation Strategies: In form validation, based on user selection, you might want to apply different validation strategies (e.g., stringent validation for high-security forms and basic validation for low-priority forms).
  • Discounting Algorithms: As described in the previous example, an e-commerce platform might offer different discounting techniques – festive season discount, buy one get one free, etc.
  • Database Connection: In applications where you might need to connect to different databases (SQL, NoSQL, Graph, etc.), each connection strategy can be encapsulated using the Strategy Pattern.

So, in summary, use the Strategy Design Pattern when you have multiple ways to achieve something and want to switch between them seamlessly without altering the code that uses these algorithms.

Advantages and Disadvantages Strategy Design Pattern in C#

The Strategy Design Pattern, like any other pattern, has its own set of advantages and disadvantages:

Advantages of Strategy Design Pattern in C#:
  1. Flexibility: Strategy Pattern promotes the Open/Closed Principle, which means you can introduce new strategies without modifying the context class or any existing strategies.
  2. Decoupling: It decouples the algorithm’s implementation from the client class. As a result, the system becomes more modular and easier to maintain.
  3. Switching Strategies at Runtime: The pattern allows you to switch strategies on the fly during runtime, providing dynamic behavior to the client.
  4. Testing: By decoupling the client from the strategies, you can independently test each strategy without needing the client. This makes unit testing more straightforward.
  5. Reusable: The strategies can be reused across different contexts. For instance, a compression algorithm strategy used in one application can be reused in another without modification.
  6. Avoids Conditional Statements: Without the Strategy Pattern, you might have to use several conditional statements to decide which algorithm to run. With this pattern, you avoid that, making the code more readable and maintainable.
Disadvantages of Strategy Design Pattern in C#:
  1. Overhead: For simple scenarios, introducing the Strategy Pattern can lead to unnecessary classes, adding complexity and overhead.
  2. Learning Curve: If there are many strategies, and a developer is new to the system, it might be slightly more challenging to understand which strategy to use and when.
  3. Client-Strategy Communication: Sometimes, the strategy might need to access some data from the client. This can be tricky as the pattern generally promotes decoupling. You might have to provide more context to the strategy, leading to tighter coupling than desired.
  4. Initialization Overhead: Each strategy, when used, would often be instantiated as a new object. This can create a performance overhead, especially if strategies are frequently changed at runtime.
  5. Potential Duplication: If not designed carefully, there might be some overlapping code among strategies. This could lead to duplication, which can be a maintenance concern.

In conclusion, while the Strategy Pattern offers many advantages related to flexibility, maintainability, and testability, ensuring it’s the right fit for the given problem is essential. Using it unnecessarily can lead to added complexity. As with any design pattern, properly understanding the problem domain and the pattern itself is crucial before deciding on its application.

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 *