The Strategy Design Pattern is a behavioral pattern that defines a group of related algorithms, encapsulates each one in a separate class, and makes them interchangeable. It allows the algorithm to vary independently from the client that uses it, enabling behavior changes at runtime without altering existing code.
- Encapsulates different algorithms into separate strategy classes, allowing dynamic selection or switching at runtime.
- Promotes flexibility by reducing complex conditional logic and making code easier to maintain.
Example: A payment system where a user (client) selects a payment method, and the system (context) applies a strategy like Credit Card, UPI, or PayPal to process the payment.

In the Diagram
- The Client interacts with the Context and decides which strategy to use.
- The Context does not implement the algorithm itself but delegates the task to a selected Strategy (A, B, or C).
- Different strategies can be switched easily without changing the client or context, ensuring flexibility.
Real-Life Software Applications
Some real-world examples where the Strategy Pattern is commonly used are:
- Multiple Payment Methods: E-commerce platforms use different payment strategies (Credit Card, PayPal, UPI, etc.), each with its own processing logic. The system selects the appropriate strategy at runtime based on user choice.
- File Compression Tools: Applications provide multiple compression options (ZIP, GZIP, TAR), allowing users to choose the desired compression strategy dynamically.
Components
The Strategy Design Pattern consists of key components that work together to define and use interchangeable algorithms.

1. Context
Acts as an intermediary between the client and the strategy, delegating tasks to the selected strategy.
- Holds a reference to a strategy object and uses it to perform operations.
- Allows switching strategies without changing its own code.
2. Strategy Interface
Defines a common interface that all concrete strategies must implement.
- Ensures consistency so all strategies are interchangeable.
- Promotes flexibility by decoupling context from implementations.
3. Concrete Strategies
Provide specific implementations of the strategy interface with different algorithms or behaviors.
- Encapsulate the actual logic of each algorithm.
- Can be selected and replaced based on requirements.
4. Client
Responsible for selecting and configuring the appropriate strategy for the context.
- Decides which strategy to use based on the problem.
- Passes the chosen strategy to the context for execution.
Working
The Strategy pattern works by delegating a specific task to interchangeable algorithm classes.
- A Strategy interface defines a common method for all algorithms.
- Concrete strategy classes implement this interface with different behaviors.
- The context class holds a reference to a strategy object.
- At runtime, the client selects or changes the strategy, and the context uses it to perform the task.
Uses
The Strategy pattern is used when an application needs to choose different behaviors or algorithms dynamically based on context.
- Selecting different algorithms at runtime (e.g., payment methods, sorting strategies)
- Eliminating large conditional statements (if-else or switch cases)
- Making behavior easily extendable without modifying existing code
Implementation Example
Problem Statement
Consider a sorting application where we need to sort a list of integers. However, the sorting algorithm to be used may vary depending on factors such as the size of the list and the desired performance characteristics.
Challenges Without Using Strategy Pattern:
- Limited Flexibility: Implementing sorting algorithms directly within the main sorting class can make the code inflexible. Adding new sorting algorithms or changing existing ones would require modifying the main class, which violates the Open/Closed Principle.
- Code Duplication: Without a clear structure, you may end up duplicating sorting logic to handle different algorithms.
- Hard-Coded Logic: Implementing sorting logic directly within the main sorting class can make the code rigid and difficult to extend or modify.
Benefits of Using the Strategy Pattern to solve above challenges
Here's how the Strategy Pattern helps:
- Code Reusability: By encapsulating sorting algorithms into separate strategy classes, you can reuse these strategies across different parts of the system. This reduces code duplication and promotes maintainability.
- Flexibility and Extensibility: The Strategy Pattern makes it simple to adapt or add new sorting algorithms without changing the existing code. Since each strategy is independent, it is possible to change or expand it without impacting other system components.
- Separation of Concerns: The Strategy Pattern separates sorting logic into distinct strategy classes, which encourages a clear division of responsibilities. As a result, the code is easier to test, and maintain.

This example shows the practical application of the design pattern using code.
1. Context(SortingContext)
#include <iostream>
using namespace std;
// Strategy Interface (Abstract Class)
class SortingStrategy {
public:
virtual void sort(int arr[], int size) = 0; // pure virtual function
virtual ~SortingStrategy() {} // virtual destructor
};
// Context Class
class SortingContext {
private:
SortingStrategy* sortingStrategy;
public:
// Constructor
SortingContext(SortingStrategy* strategy) {
this->sortingStrategy = strategy;
}
// Setter to change strategy
void setSortingStrategy(SortingStrategy* strategy) {
this->sortingStrategy = strategy;
}
// Perform sort
void performSort(int arr[], int size) {
if (sortingStrategy)
sortingStrategy->sort(arr, size);
}
};
import java.util.Arrays;
// Strategy Interface (Abstract Class)
interface SortingStrategy {
void sort(String[] arr, int size); // pure virtual function
}
// Context Class
class SortingContext {
private SortingStrategy sortingStrategy;
// Constructor
public SortingContext(SortingStrategy strategy) {
this.sortingStrategy = strategy;
}
// Setter to change strategy
public void setSortingStrategy(SortingStrategy strategy) {
this.sortingStrategy = strategy;
}
// Perform sort
public void performSort(String[] arr, int size) {
if (sortingStrategy!= null)
sortingStrategy.sort(arr, size);
}
}
// Example concrete strategy
class AlphabeticalSort implements SortingStrategy {
@Override
public void sort(String[] arr, int size) {
Arrays.sort(arr);
}
}
from abc import ABC, abstractmethod
class SortingStrategy(ABC):
@abstractmethod
def sort(self, array):
pass
class SortingContext:
def __init__(self, sorting_strategy):
self.sorting_strategy = sorting_strategy
def set_sorting_strategy(self, sorting_strategy):
self.sorting_strategy = sorting_strategy
def perform_sort(self, array):
self.sorting_strategy.sort(array)
class SortingStrategy {
sort(array) {
throw new Error('sort method must be implemented');
}
}
class SortingContext {
constructor(sortingStrategy) {
this.sortingStrategy = sortingStrategy;
}
setSortingStrategy(sortingStrategy) {
this.sortingStrategy = sortingStrategy;
}
performSort(array) {
this.sortingStrategy.sort(array);
}
}
2. Strategy Interface(SortingStrategy)
public interface SortingStrategy {
void sort(int[] array);
}
public interface SortingStrategy {
void sort(int[] array);
// Implement sorting logic here
}
from abc import ABC, abstractmethod
class SortingStrategy(ABC):
@abstractmethod
def sort(self, array):
pass
# Implement sorting logic here
def sort(self, array):
array.sort()
const SortingStrategy = {
sort: function(array) {
// Implement sorting logic here
array.sort();
}
};
3. Concrete Strategies
#include <iostream>
using namespace std;
// Assuming SortingStrategy is already defined as an abstract class
// BubbleSortStrategy
class BubbleSortStrategy : public SortingStrategy {
public:
void sort(int arr[], int size) override {
// Implement Bubble Sort algorithm
cout << "Sorting using Bubble Sort" << endl;
}
};
// MergeSortStrategy
class MergeSortStrategy : public SortingStrategy {
public:
void sort(int arr[], int size) override {
// Implement Merge Sort algorithm
cout << "Sorting using Merge Sort" << endl;
}
};
// QuickSortStrategy
class QuickSortStrategy : public SortingStrategy {
public:
void sort(int arr[], int size) override {
// Implement Quick Sort algorithm
cout << "Sorting using Quick Sort" << endl;
}
};
// BubbleSortStrategy
public class BubbleSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// Implement Bubble Sort algorithm
System.out.println("Sorting using Bubble Sort");
}
}
// MergeSortStrategy
public class MergeSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// Implement Merge Sort algorithm
System.out.println("Sorting using Merge Sort");
}
}
// QuickSortStrategy
public class QuickSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// Implement Quick Sort algorithm
System.out.println("Sorting using Quick Sort");
}
}
class BubbleSortStrategy:
def sort(self, array):
# Implement Bubble Sort algorithm
print("Sorting using Bubble Sort")
class MergeSortStrategy:
def sort(self, array):
# Implement Merge Sort algorithm
print("Sorting using Merge Sort")
class QuickSortStrategy:
def sort(self, array):
# Implement Quick Sort algorithm
print("Sorting using Quick Sort")
class BubbleSortStrategy {
sort(array) {
// Implement Bubble Sort algorithm
console.log("Sorting using Bubble Sort");
}
}
class MergeSortStrategy {
sort(array) {
// Implement Merge Sort algorithm
console.log("Sorting using Merge Sort");
}
}
class QuickSortStrategy {
sort(array) {
// Implement Quick Sort algorithm
console.log("Sorting using Quick Sort");
}
}
4. Client Component
#include <iostream>
using namespace std;
int main() {
// Create strategies
SortingStrategy* bubble = new BubbleSortStrategy();
SortingStrategy* merge = new MergeSortStrategy();
SortingStrategy* quick = new QuickSortStrategy();
// Create SortingContext with BubbleSortStrategy
SortingContext sortingContext(bubble);
int array1[] = {5, 2, 9, 1, 5};
sortingContext.performSort(array1, 5); // Output: Sorting using Bubble Sort
// Change strategy to MergeSortStrategy
sortingContext.setSortingStrategy(merge);
int array2[] = {8, 3, 7, 4, 2};
sortingContext.performSort(array2, 5); // Output: Sorting using Merge Sort
// Change strategy to QuickSortStrategy
sortingContext.setSortingStrategy(quick);
int array3[] = {6, 1, 3, 9, 5};
sortingContext.performSort(array3, 5); // Output: Sorting using Quick Sort
// Cleanup (important in C++)
delete bubble;
delete merge;
delete quick;
return 0;
}
public interface SortingStrategy {
void sort(String[] array);
}
class BubbleSortStrategy implements SortingStrategy {
@Override
public void sort(String[] array) {
System.out.println("Sorting using Bubble Sort");
// Bubble sort implementation
}
}
class MergeSortStrategy implements SortingStrategy {
@Override
public void sort(String[] array) {
System.out.println("Sorting using Merge Sort");
// Merge sort implementation
}
}
class QuickSortStrategy implements SortingStrategy {
@Override
public void sort(String[] array) {
System.out.println("Sorting using Quick Sort");
// Quick sort implementation
}
}
class SortingContext {
private SortingStrategy strategy;
public SortingContext(SortingStrategy strategy) {
this.strategy = strategy;
}
public void performSort(String[] array) {
strategy.sort(array);
}
public void setSortingStrategy(SortingStrategy strategy) {
this.strategy = strategy;
}
}
public class Client {
public static void main(String[] args) {
// Create SortingContext with BubbleSortStrategy
SortingContext sortingContext = new SortingContext(new BubbleSortStrategy());
String[] array1 = {"cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"};
sortingContext.performSort(array1); // Output: Sorting using Bubble Sort
// Change strategy to MergeSortStrategy
sortingContext.setSortingStrategy(new MergeSortStrategy());
String[] array2 = {"cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"};
sortingContext.performSort(array2); // Output: Sorting using Merge Sort
// Change strategy to QuickSortStrategy
sortingContext.setSortingStrategy(new QuickSortStrategy());
String[] array3 = {"cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"};
sortingContext.performSort(array3); // Output: Sorting using Quick Sort
}
}
from abc import ABC, abstractmethod
class SortingStrategy(ABC):
@abstractmethod
def sort(self, array):
pass
class BubbleSortStrategy(SortingStrategy):
def sort(self, array):
print('Sorting using Bubble Sort')
# Bubble sort implementation
class MergeSortStrategy(SortingStrategy):
def sort(self, array):
print('Sorting using Merge Sort')
# Merge sort implementation
class QuickSortStrategy(SortingStrategy):
def sort(self, array):
print('Sorting using Quick Sort')
# Quick sort implementation
class SortingContext:
def __init__(self, strategy):
self.strategy = strategy
def perform_sort(self, array):
self.strategy.sort(array)
def set_sorting_strategy(self, strategy):
self.strategy = strategy
# Create SortingContext with BubbleSortStrategy
sorting_context = SortingContext(BubbleSortStrategy())
array1 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml']
sorting_context.perform_sort(array1) # Output: Sorting using Bubble Sort
# Change strategy to MergeSortStrategy
sorting_context.set_sorting_strategy(MergeSortStrategy())
array2 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml']
sorting_context.perform_sort(array2) # Output: Sorting using Merge Sort
# Change strategy to QuickSortStrategy
sorting_context.set_sorting_strategy(QuickSortStrategy())
array3 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml']
sorting_context.perform_sort(array3) # Output: Sorting using Quick Sort
class SortingStrategy {
sort(array) {}
}
class BubbleSortStrategy extends SortingStrategy {
sort(array) {
console.log('Sorting using Bubble Sort');
// Bubble sort implementation
}
}
class MergeSortStrategy extends SortingStrategy {
sort(array) {
console.log('Sorting using Merge Sort');
// Merge sort implementation
}
}
class QuickSortStrategy extends SortingStrategy {
sort(array) {
console.log('Sorting using Quick Sort');
// Quick sort implementation
}
}
class SortingContext {
constructor(strategy) {
this.strategy = strategy;
}
performSort(array) {
this.strategy.sort(array);
}
setSortingStrategy(strategy) {
this.strategy = strategy;
}
}
// Create SortingContext with BubbleSortStrategy
let sortingContext = new SortingContext(new BubbleSortStrategy());
let array1 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml'];
sortingContext.performSort(array1); // Output: Sorting using Bubble Sort
// Change strategy to MergeSortStrategy
sortingContext.setSortingStrategy(new MergeSortStrategy());
let array2 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml'];
sortingContext.performSort(array2); // Output: Sorting using Merge Sort
// Change strategy to QuickSortStrategy
sortingContext.setSortingStrategy(new QuickSortStrategy());
let array3 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml'];
sortingContext.performSort(array3); // Output: Sorting using Quick Sort
Complete code for the above example
#include <iostream>
#include <vector>
class SortingStrategy {
public:
virtual void sort(std::vector<std::string>& array) = 0;
};
class BubbleSortStrategy : public SortingStrategy {
public:
void sort(std::vector<std::string>& array) override {
std::cout << "Sorting using Bubble Sort" << std::endl;
// Actual Bubble Sort Logic here
}
};
class MergeSortStrategy : public SortingStrategy {
public:
void sort(std::vector<std::string>& array) override {
std::cout << "Sorting using Merge Sort" << std::endl;
// Actual Merge Sort Logic here
}
};
class QuickSortStrategy : public SortingStrategy {
public:
void sort(std::vector<std::string>& array) override {
std::cout << "Sorting using Quick Sort" << std::endl;
// Actual Quick Sort Logic here
}
};
class SortingContext {
private:
SortingStrategy* sortingStrategy;
public:
SortingContext(SortingStrategy* sortingStrategy) : sortingStrategy(sortingStrategy) {}
void setSortingStrategy(SortingStrategy* sortingStrategy) {
this->sortingStrategy = sortingStrategy;
}
void performSort(std::vector<std::string>& array) {
sortingStrategy->sort(array);
}
};
int main() {
std::vector<std::string> array1 = {"cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"};
SortingContext sortingContext(new BubbleSortStrategy());
sortingContext.performSort(array1); // Output: Sorting using Bubble Sort
sortingContext.setSortingStrategy(new MergeSortStrategy());
std::vector<std::string> array2 = {"cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"};
sortingContext.performSort(array2); // Output: Sorting using Merge Sort
sortingContext.setSortingStrategy(new QuickSortStrategy());
std::vector<std::string> array3 = {"cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"};
sortingContext.performSort(array3); // Output: Sorting using Quick Sort
return 0;
}
class SortingContext {
private SortingStrategy sortingStrategy;
public SortingContext(SortingStrategy sortingStrategy) {
this.sortingStrategy = sortingStrategy;
}
public void setSortingStrategy(SortingStrategy sortingStrategy) {
this.sortingStrategy = sortingStrategy;
}
public void performSort(int[] array) {
sortingStrategy.sort(array);
}
}
// SortingStrategy.java
interface SortingStrategy {
void sort(int[] array);
}
// BubbleSortStrategy.java
class BubbleSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// Implement Bubble Sort algorithm
System.out.println("Sorting using Bubble Sort");
// Actual Bubble Sort Logic here
}
}
// MergeSortStrategy.java
class MergeSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// Implement Merge Sort algorithm
System.out.println("Sorting using Merge Sort");
// Actual Merge Sort Logic here
}
}
// QuickSortStrategy.java
class QuickSortStrategy implements SortingStrategy {
@Override
public void sort(int[] array) {
// Implement Quick Sort algorithm
System.out.println("Sorting using Quick Sort");
// Actual Quick Sort Logic here
}
}
// Client.java
public class Client {
public static void main(String[] args) {
// Create SortingContext with BubbleSortStrategy
SortingContext sortingContext = new SortingContext(new BubbleSortStrategy());
int[] array1 = {5, 2, 9, 1, 5};
sortingContext.performSort(array1); // Output: Sorting using Bubble Sort
// Change strategy to MergeSortStrategy
sortingContext.setSortingStrategy(new MergeSortStrategy());
int[] array2 = {8, 3, 7, 4, 2};
sortingContext.performSort(array2); // Output: Sorting using Merge Sort
// Change strategy to QuickSortStrategy
sortingContext.setSortingStrategy(new QuickSortStrategy());
int[] array3 = {6, 1, 3, 9, 5};
sortingContext.performSort(array3); // Output: Sorting using Quick Sort
}
}
from abc import ABC, abstractmethod
class SortingStrategy(ABC):
@abstractmethod
def sort(self, array):
pass
class BubbleSortStrategy(SortingStrategy):
def sort(self, array):
print('Sorting using Bubble Sort')
# Actual Bubble Sort Logic here
class MergeSortStrategy(SortingStrategy):
def sort(self, array):
print('Sorting using Merge Sort')
# Actual Merge Sort Logic here
class QuickSortStrategy(SortingStrategy):
def sort(self, array):
print('Sorting using Quick Sort')
# Actual Quick Sort Logic here
class SortingContext:
def __init__(self, sorting_strategy):
self.sorting_strategy = sorting_strategy
def set_sorting_strategy(self, sorting_strategy):
self.sorting_strategy = sorting_strategy
def perform_sort(self, array):
self.sorting_strategy.sort(array)
# Client
array1 = ["cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"]
sorting_context = SortingContext(BubbleSortStrategy())
sorting_context.perform_sort(array1) # Output: Sorting using Bubble Sort
sorting_context.set_sorting_strategy(MergeSortStrategy())
array2 = ["cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"]
sorting_context.perform_sort(array2) # Output: Sorting using Merge Sort
sorting_context.set_sorting_strategy(QuickSortStrategy())
array3 = ["cpp","c","java","python3","csharp","html","css","javascript","php","cpp14","cobol","dart","go","julia","kotlin","lisp","matlab","node","objc","perl","r","rust","ruby","scala","swift","solidity","xml"]
sorting_context.perform_sort(array3) # Output: Sorting using Quick Sort
class SortingContext {
constructor(sortingStrategy) {
this.sortingStrategy = sortingStrategy;
}
setSortingStrategy(sortingStrategy) {
this.sortingStrategy = sortingStrategy;
}
performSort(array) {
this.sortingStrategy.sort(array);
}
}
class SortingStrategy {
sort(array) {
throw new Error('This method should be overridden!');
}
}
class BubbleSortStrategy extends SortingStrategy {
sort(array) {
console.log('Sorting using Bubble Sort');
// Actual Bubble Sort Logic here
}
}
class MergeSortStrategy extends SortingStrategy {
sort(array) {
console.log('Sorting using Merge Sort');
// Actual Merge Sort Logic here
}
}
class QuickSortStrategy extends SortingStrategy {
sort(array) {
console.log('Sorting using Quick Sort');
// Actual Quick Sort Logic here
}
}
// Client
const sortingContext = new SortingContext(new BubbleSortStrategy());
const array1 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml'];
sortingContext.performSort(array1); // Output: Sorting using Bubble Sort
sortingContext.setSortingStrategy(new MergeSortStrategy());
const array2 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml'];
sortingContext.performSort(array2); // Output: Sorting using Merge Sort
sortingContext.setSortingStrategy(new QuickSortStrategy());
const array3 = ['cpp','c','java','python3','csharp','html','css','javascript','php','cpp14','cobol','dart','go','julia','kotlin','lisp','matlab','node','objc','perl','r','rust','ruby','scala','swift','solidity','xml'];
sortingContext.performSort(array3); // Output: Sorting using Quick Sort
Output
Sorting using Bubble Sort Sorting using Merge Sort Sorting using Quick Sort
Advantages
This pattern improves flexibility and maintainability by separating behavior from the main logic.
- Promotes open/closed principle by allowing new strategies to be added easily
- Makes code cleaner and easier to maintain
- Enables runtime behavior changes without code modification
Limitations
While flexible, the pattern can introduce additional complexity in the application design.
- Increases the number of classes and objects in the system.
- Clients need to understand and select the appropriate strategy implementation.
- May cause slight performance overhead due to extra object creation and method calls.