- C++ Home
- C++ Overview
- C++ Environment Setup
- C++ Basic Syntax
- C++ Comments
- C++ Hello World
- C++ Omitting Namespace
- C++ Tokens
- C++ Constants/Literals
- C++ Keywords
- C++ Identifiers
- C++ Data Types
- C++ Numeric Data Types
- C++ Character Data Type
- C++ Boolean Data Type
- C++ Variable Types
- C++ Variable Scope
- C++ Multiple Variables
- C++ Input Output Operations
- C++ Basic Input/Output
- C++ Cin
- C++ Cout
- C++ Manipulators
- Type System & Data Representation
- C++ Modifier Types
- C++ Storage Classes
- C++ Constexpr Specifier
- C++ Numbers
- C++ Enumeration
- C++ Enum Class
- C++ References
- C++ Date & Time
- C++ Operators
- C++ Operators
- C++ Arithmetic Operators
- C++ Relational Operators
- C++ Logical Operators
- C++ Bitwise Operators
- C++ Assignment Operators
- C++ sizeof Operator
- C++ Conditional Operator
- C++ Comma Operator
- C++ Member Operators
- C++ Casting Operators
- C++ Pointer Operators
- C++ Operators Precedence
- C++ Unary Operators
- C++ Scope Resolution Operator
- C++ Control Statements
- C++ Decision Making
- C++ if Statement
- C++ if else Statement
- C++ Nested if Statements
- C++ switch Statement
- C++ Nested switch Statements
- C++ Loop Types
- C++ while Loop
- C++ for Loop
- C++ do while Loop
- C++ Foreach Loop
- C++ Nested Loops
- C++ Jump Statements
- C++ break Statement
- C++ continue Statement
- C++ goto Statement
- C++ Return Values
- C++ Strings
- C++ Strings
- C++ Loop Through a String
- C++ String Length
- C++ String Concatenation
- C++ String Comparison
- C++ Functions
- C++ Functions
- C++ Multiple Function Parameters
- C++ Recursive Function
- C++ Function Overloading
- C++ Function Overriding
- C++ Default Arguments
- C++ Arrays
- C++ Arrays
- C++ Multidimensional Arrays
- C++ Pointer to an Array
- C++ Passing Arrays to Functions
- C++ Return Array from Functions
- C++ Array Decay
- C++ Structure & Union
- C++ Structures
- C++ Unions
- C++ Class and Objects
- C++ Object Oriented
- C++ Classes & Objects
- C++ Class Member Functions
- C++ Class Access Modifiers
- C++ Static Class Members
- C++ Static Data Members
- C++ Static Member Function
- C++ Inline Functions
- C++ this Pointer
- C++ Friend Functions
- C++ Pointer to Classes
- C++ Constructors
- C++ Constructor & Destructor
- C++ Default Constructors
- C++ Parameterized Constructors
- C++ Copy Constructor
- C++ Constructor Overloading
- C++ Constructor with Default Arguments
- C++ Delegating Constructors
- C++ Constructor Initialization List
- C++ Dynamic Initialization Using Constructors
- C++ Destructors
- C++ Virtual Destructor
- C++ Inheritance
- C++ Inheritance
- C++ Multiple Inheritance
- C++ Multilevel Inheritance
- C++ Object-oriented
- C++ Overloading
- C++ Polymorphism
- C++ Abstraction
- C++ Encapsulation
- C++ Interfaces
- C++ Virtual Function
- C++ Pure Virtual Functions & Abstract Classes
- C++ Override Specifiers
- C++ Final Specifiers
- C++ Design Patterns
- C++ Creational Design Patterns
- C++ Singleton Design Pattern
- C++ Factory Method Design Pattern
- C++ Abstract Factory Pattern
- C++ Prototype Design Pattern
- C++ Structural Design Patterns
- C++ Facade Design Pattern
- C++ Iterator Design Pattern
- C++ Mediator Design Pattern
- C++ Memento Design Pattern
- C++ Observer Design Pattern
- C++ State Design Pattern
- C++ Strategy Design Pattern
- C++ Template Method Design Pattern
- C++ Visitor Design Pattern
- C++ Behavioural Design Pattern
- C++ File Handling
- C++ Files and Streams
- C++ Reading From File
- C++ Advanced
- C++ Exception Handling
- C++ Dynamic Memory
- C++ Move Semantics
- C++ Namespaces
- C++ Templates
- C++ Preprocessor
- C++ Signal Handling
- C++ Multithreading
- C++ Web Programming
- C++ Socket Programming
- C++ Concurrency
- C++ Advanced Concepts
- C++ Lambda Expression
- C++ nullptr
- C++ unordered_multiset
- C++ Chain of Responsibility
- C++ Structural Design Patterns
- C++ Adapter Pattern
- C++ Bridge Pattern
- C++ Composite Pattern
- C++ Decorator Pattern
- C++ Flyweight Pattern
- C++ Command Pattern
- C++ Proxy Pattern
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.
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.
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.