Strategy Pattern in C++ Design Patterns

Explore the Strategy Pattern in C++: A comprehensive guide to defining a family of algorithms, implementing strategies with polymorphism, selecting algorithms at runtime, and avoiding code duplication. Enhance your software design skills with practical examples and expert insights.

6.10 Strategy Pattern

The Strategy Pattern is a behavioral design pattern that enables selecting an algorithm’s behavior at runtime. This pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. The Strategy Pattern allows the algorithm to vary independently from clients that use it, promoting flexibility and reusability in code.

Intent

The primary intent of the Strategy Pattern is to define a set of algorithms, encapsulate each one, and make them interchangeable. This pattern allows the algorithm to vary independently from the clients that use it. By encapsulating the algorithm, the Strategy Pattern promotes the Open/Closed Principle, enabling new strategies to be added without altering existing code.

Key Participants

  1. Strategy: This is an interface common to all supported algorithms. The Strategy interface declares operations common to all supported versions of some algorithm.

  2. ConcreteStrategy: These are classes that implement the Strategy interface. Each ConcreteStrategy implements a specific algorithm.

  3. Context: This class maintains a reference to a Strategy object and is configured with a ConcreteStrategy object. The Context class interacts with the Strategy interface to execute an algorithm defined by a ConcreteStrategy.

Applicability

Use the Strategy Pattern when:

  • You have a family of algorithms and need to choose one at runtime.
  • You want to avoid exposing complex, algorithm-specific data structures.
  • You need to replace conditional statements with polymorphism.
  • You want to encapsulate algorithms in a way that allows them to be interchangeable.

Sample Code Snippet

Let’s consider a simple example where we have different strategies for sorting a list of integers. We will define a Strategy interface, concrete strategies for different sorting algorithms, and a Context class to use these strategies.

 1#include <iostream>
 2#include <vector>
 3#include <algorithm>
 4
 5// Strategy Interface
 6class SortStrategy {
 7public:
 8    virtual ~SortStrategy() {}
 9    virtual void sort(std::vector<int>& data) = 0;
10};
11
12// Concrete Strategy for Bubble Sort
13class BubbleSort : public SortStrategy {
14public:
15    void sort(std::vector<int>& data) override {
16        for (size_t i = 0; i < data.size(); ++i) {
17            for (size_t j = 0; j < data.size() - i - 1; ++j) {
18                if (data[j] > data[j + 1]) {
19                    std::swap(data[j], data[j + 1]);
20                }
21            }
22        }
23    }
24};
25
26// Concrete Strategy for Quick Sort
27class QuickSort : public SortStrategy {
28public:
29    void sort(std::vector<int>& data) override {
30        quickSort(data, 0, data.size() - 1);
31    }
32
33private:
34    void quickSort(std::vector<int>& data, int low, int high) {
35        if (low < high) {
36            int pi = partition(data, low, high);
37            quickSort(data, low, pi - 1);
38            quickSort(data, pi + 1, high);
39        }
40    }
41
42    int partition(std::vector<int>& data, int low, int high) {
43        int pivot = data[high];
44        int i = (low - 1);
45        for (int j = low; j <= high - 1; j++) {
46            if (data[j] < pivot) {
47                i++;
48                std::swap(data[i], data[j]);
49            }
50        }
51        std::swap(data[i + 1], data[high]);
52        return (i + 1);
53    }
54};
55
56// Context
57class SortContext {
58private:
59    SortStrategy* strategy;
60
61public:
62    SortContext(SortStrategy* strategy) : strategy(strategy) {}
63
64    void setStrategy(SortStrategy* strategy) {
65        this->strategy = strategy;
66    }
67
68    void sortData(std::vector<int>& data) {
69        strategy->sort(data);
70    }
71};
72
73// Client Code
74int main() {
75    std::vector<int> data = {34, 7, 23, 32, 5, 62};
76
77    SortContext context(new BubbleSort());
78    std::cout << "Using Bubble Sort:\n";
79    context.sortData(data);
80    for (int num : data) {
81        std::cout << num << " ";
82    }
83    std::cout << std::endl;
84
85    data = {34, 7, 23, 32, 5, 62};
86    context.setStrategy(new QuickSort());
87    std::cout << "Using Quick Sort:\n";
88    context.sortData(data);
89    for (int num : data) {
90        std::cout << num << " ";
91    }
92    std::cout << std::endl;
93
94    return 0;
95}

Design Considerations

  • Encapsulation: The Strategy Pattern encapsulates the algorithm, allowing the client to choose which algorithm to use at runtime.
  • Open/Closed Principle: New strategies can be added without modifying existing code, adhering to the Open/Closed Principle.
  • Polymorphism: The Strategy Pattern uses polymorphism to switch between different algorithms.
  • Performance: Consider the performance implications of switching strategies at runtime, especially if the strategy changes frequently.

Differences and Similarities

The Strategy Pattern is often confused with the State Pattern. While both patterns involve changing behavior at runtime, the Strategy Pattern is used to switch between algorithms, whereas the State Pattern is used to change the behavior of an object based on its state.

Visualizing the Strategy Pattern

Let’s use a diagram to visualize the relationships between the Context, Strategy, and ConcreteStrategy classes.

    classDiagram
	    class Context {
	        -Strategy* strategy
	        +setStrategy(Strategy* strategy)
	        +sortData(vector<int>& data)
	    }
	
	    class Strategy {
	        <<interface>>
	        +sort(vector<int>& data)
	    }
	
	    class BubbleSort {
	        +sort(vector<int>& data)
	    }
	
	    class QuickSort {
	        +sort(vector<int>& data)
	    }
	
	    Context --> Strategy
	    Strategy <|-- BubbleSort
	    Strategy <|-- QuickSort

Try It Yourself

Experiment with the code by adding a new sorting strategy, such as Merge Sort. Implement the MergeSort class that inherits from SortStrategy and integrate it into the SortContext.

Knowledge Check

  • What is the primary intent of the Strategy Pattern?
  • How does the Strategy Pattern promote the Open/Closed Principle?
  • What is the difference between the Strategy Pattern and the State Pattern?

Embrace the Journey

Remember, mastering design patterns is a journey. As you explore the Strategy Pattern, consider how it can be applied to your projects to enhance flexibility and maintainability. Keep experimenting, stay curious, and enjoy the process of learning and applying design patterns in C++.

Quiz Time!

Loading quiz…
Revised on Thursday, April 23, 2026