Strategy Design Pattern in C++



The Strategy Design Pattern is a simple and powerful way to organize your code when you have different ways to perform the same task. It defines a family of algorithms, places each one in its own separate class, and lets you switch between them easily. This means you can change the algorithm's behavior without touching the main code that uses it.

For example, imagine you have a navigation app that can show routes based on different preferences: the fastest route, the shortest route, or the most scenic route. With the Strategy Design Pattern, you can create a separate class for each type of route and simply switch between them whenever needed, without changing how the main app works.

Strategy Design Pattern Illustration

Key Components of the Strategy Design Pattern

The Strategy Design Pattern is built around a few main parts that make the code more flexible, organized, and easy to maintain. Let's look at them one by one −

  • Strategy Interface − This defines a common method that every strategy (or algorithm) must follow. It ensures that all the different strategies can be used in the same way, no matter which one you choose.
  • Concrete Strategies − These are the actual classes that implement the Strategy Interface. Each one represents a different algorithm or way of doing a task. For example, one strategy might calculate the fastest route, while another finds the most scenic one.
  • Context − This is the main class that uses one of the strategies. It keeps a reference to a Strategy object and asks it to perform the task. The Context doesn't care which strategy it's using, it just knows that it can call the same method on any of them.

In short, the Strategy Design Pattern helps you write code that's easier to update, cleaner to read, and simpler to extend. When a new way of doing something comes along, you can just add a new strategy class instead of rewriting your existing code.

C++ Implementation of the Strategy Design Pattern

In this section, we will see how to implement the Strategy Design Pattern in C++ with a simple and easy-to-understand example. We'll create a Context class that can use different strategies to perform a calculation. Each strategy will be written in its own class, making the program flexible enough to switch between different strategies whenever needed it without changing the rest of the code.

Steps to Implement the Strategy Design Pattern in C++

  • Define the Strategy Interface − Start by creating an abstract class that defines a common method for the algorithm. This interface acts like a blueprint that every strategy class will follow this same structure.
  • Implement Concrete Strategies − Create separate classes that inherit from the Strategy Interface and provide their own version of the algorithm. Each class will represent a different way of performing the same task.
  • Create the Context Class − This is the main class that will use one of the strategies. It holds a reference to a Strategy object and uses it to perform the calculation. The Context doesn't care which strategy it's using and it just calls the same method.
  • Use the Strategy Pattern − In the main function, create objects for the Context and the different Strategy classes. Show how the Context can switch between strategies dynamically for example, changing from addition to multiplication — without rewriting any logic in the Context itself.

By following these steps, you'll learn how the Strategy Design Pattern helps make your code cleaner, easier to extend, and more flexible when you need to change or add new behaviors.

C++ Example Code of the Strategy Design Pattern

Below is a simple C++ implementation of the Strategy Design Pattern. In this example, we have a context class that can use different strategies for performing calculations (addition and subtraction).

#include <iostream>
using namespace std;

// Strategy Interface

class Strategy {
public:
   virtual int doOperation(int a, int b) = 0;
   virtual ~Strategy() {}
};

// Concrete Strategy for Addition

class Addition : public Strategy {
public:
   int doOperation(int a, int b) override {
      return a + b;
   }
};

// Concrete Strategy for Subtraction

class Subtraction : public Strategy {
public:
   int doOperation(int a, int b) override {
      return a -b;
   }
};

// Context Class

class Context {
private:
   Strategy* strategy;
public:
   Context(Strategy* strategy) : strategy(strategy) {}
   
   void setStrategy(Strategy* strategy) {
      this->strategy = strategy;
   }
   
   int executeStrategy(int a, int b) {
      return strategy->doOperation(a, b);
   }
};

int main() {
   Context* context = new Context(new Addition());
   cout << "10 + 5 = " << context->executeStrategy(10, 5) << endl;

   context->setStrategy(new Subtraction());
   cout << "10 -5 = " << context->executeStrategy(10, 5) << endl;

   delete context;
   return 0;
}

Following is the output of the above code −

10 + 5 = 15
10 -5 = 5

Pros and Cons of the Strategy Design Pattern

Like most design patterns, the Strategy Design Pattern has both advantages and disadvantages. Understanding both sides helps you decide when it's actually worth using in a project.

Pros Cons
This pattern gives you the freedom to change algorithms while the program is running. You don't need to edit the main class; you can just switch one strategy for another, which keeps the code flexible and easy to adapt. Each strategy needs its own class, which can increase the number of files in your project. This might make the codebase feel more cluttered and harder to navigate in larger applications.
Since every algorithm is placed in its own class, it's much easier to update or fix without affecting other parts of the code. This separation makes the program cleaner and easier to maintain. For small or simple programs, using this pattern can feel like too much work. Creating multiple classes for something straightforward might make the code more complex than necessary.
Strategies can be reused in different parts of your program or even in other projects. This helps you avoid repeating the same logic and keeps your code more organized. Since the program has to go through an extra layer to reach the strategy object, there can be a small amount of performance overhead. It's usually minor, but worth noting in performance-critical applications.

Overall, the Strategy Design Pattern is a practical and clean way to keep your code flexible and easy to manage. It's especially useful when your program needs to switch between different algorithms or behaviors, but for very simple projects, it might be better to stick with a straightforward approach.

Real-World Examples of the Strategy Design Pattern

The Strategy Design Pattern is used in many software programs to make it easy to change the way something works. Here are some simple examples of where it can be used −

  • In payment systems, such as online shopping apps, different payment methods like credit card, PayPal, or cryptocurrency can each be written in a separate class. The program can then choose the right payment method based on what the user wants.
  • In programs that need to sort data, different sorting methods like quicksort, mergesort, or bubblesort can be used as separate strategies. The program can decide which one to use depending on how big or small the data is.
  • In file compression software, different compression types such as ZIP, RAR, or TAR can each be written separately. The user can choose which one to use without changing the main program.
  • In video games, different character behaviors like attacking, defending, or staying still can each be made as their own strategy. The game can switch between them based on what is happening during the game.
Strategy Design Pattern Applications Illustration

Conclusion

In this chapter, we explored the Strategy Design Pattern, its key components, and how it helps in making your code more flexible and easier to manage. We also saw some real-world examples where this pattern can be effectively applied.

Advertisements