🤔 What is the Strategy Pattern?
The Strategy Pattern is a behavioral design pattern that defines a family of algorithms, encapsulates each one, and makes them interchangeable. This enables the selection of an algorithm at runtime based on the specific context.
In simple terms, the Strategy Pattern allows you to dynamically change the behavior of an object without modifying its client code.
🧠 Real-Life Analogy
Think of ordering food online. You have various payment options:
- Credit Card 🏦
- PayPal 💳
- Cash on Delivery 💵
You don't need to alter the food ordering process itself; you simply switch between payment methods.
✅ When to Use
- When you have several ways to perform a similar task and want the client to choose one at runtime.
- When you want to eliminate complex conditional logic (like
if-else
orswitch-case
). - When you need interchangeable algorithms.
🏗 Example Use Case: Sorting Strategies
Consider a Sorting System where the algorithm can be Bubble Sort, Quick Sort, or Merge Sort.
🛠️ Java Implementation of Strategy Pattern
✅ 1. Define the Strategy Interface
public interface SortStrategy {
void sort(int[] array);
}
✅ 2. Create Concrete Strategies
🌀 Bubble Sort
public class BubbleSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Bubble Sort...");
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
// Swap
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
🚀 Quick Sort
public class QuickSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Quick Sort...");
quickSort(array, 0, array.length - 1);
}
private void quickSort(int[] array, int low, int high) {
if (low < high) {
int pivotIndex = partition(array, low, high);
quickSort(array, low, pivotIndex - 1);
quickSort(array, pivotIndex + 1, high);
}
}
private int partition(int[] array, int low, int high) {
int pivot = array[high];
int i = (low - 1);
for (int j = low; j < high; j++) {
if (array[j] <= pivot) {
i++;
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
int temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
}
🌐 Merge Sort
public class MergeSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Merge Sort...");
mergeSort(array, 0, array.length - 1);
}
private void mergeSort(int[] array, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(array, left, mid);
mergeSort(array, mid + 1, right);
merge(array, left, mid, right);
}
}
private void merge(int[] array, int left, int mid, int right) {
int[] leftArray = new int[mid - left + 1];
int[] rightArray = new int[right - mid];
System.arraycopy(array, left, leftArray, 0, mid - left + 1);
System.arraycopy(array, mid + 1, rightArray, 0, right - mid);
int i = 0, j = 0;
int k = left;
while (i < leftArray.length && j < rightArray.length) {
if (leftArray[i] <= rightArray[j]) {
array[k] = leftArray[i];
i++;
} else {
array[k] = rightArray[j];
j++;
}
k++;
}
while (i < leftArray.length) {
array[k] = leftArray[i];
i++;
k++;
}
while (j < rightArray.length) {
array[k] = rightArray[j];
j++;
k++;
}
}
}
✅ 3. Context Class
public class SorterContext {
private SortStrategy sortStrategy;
public SorterContext(SortStrategy sortStrategy) {
this.sortStrategy = sortStrategy;
}
public void setSortStrategy(SortStrategy sortStrategy) {
this.sortStrategy = sortStrategy;
}
public void executeSort(int[] array) {
sortStrategy.sort(array);
}
}
✅ 4. Client Code
public class StrategyPatternDemo {
public static void main(String[] args) {
int[] array = {5, 3, 8, 1, 2};
SorterContext context = new SorterContext(new BubbleSortStrategy());
context.executeSort(array); // Using Bubble Sort...
System.out.println("Array after Bubble Sort: " + Arrays.toString(array));
// Switching strategy to QuickSort
context.setSortStrategy(new QuickSortStrategy());
context.executeSort(array); // Using Quick Sort...
System.out.println("Array after Quick Sort: " + Arrays.toString(array));
// Switching strategy to MergeSort
context.setSortStrategy(new MergeSortStrategy());
context.executeSort(array); // Using Merge Sort...
System.out.println("Array after Merge Sort: " + Arrays.toString(array));
}
}
🧪 Output
Using Bubble Sort...
Array after Bubble Sort: [1, 2, 3, 5, 8]
Using Quick Sort...
Array after Quick Sort: [1, 2, 3, 5, 8]
Using Merge Sort...
Array after Merge Sort: [1, 2, 3, 5, 8]
📦 Structure Recap
+---------------------+ +-----------------------+
| SorterContext |<>--| SortStrategy |
+---------------------+ +-----------------------+
| - sortStrategy | | + sort(array) |
| + setSortStrategy() | +-----------------------+
| + executeSort() | ^
+---------------------+ |
+---------------------+
| BubbleSortStrategy |
+---------------------+
| + sort(array) |
+---------------------+
^
|
+---------------------+
| QuickSortStrategy |
+---------------------+
| + sort(array) |
+---------------------+
^
|
+---------------------+
| MergeSortStrategy |
+---------------------+
| + sort(array) |
+---------------------+
🧠 Key Benefits
Benefit | Explanation |
---|---|
Flexibility | Dynamically select algorithms or strategies |
Open/Closed Principle | Add new strategies without changing existing code |
Reusability | Common functionality shared among different algorithms |
Easy to Understand | Avoids complex conditional chains for selecting strategies |
🛠️ Real Use Cases
- Sorting Algorithms (BubbleSort, QuickSort, MergeSort)
- Payment Methods (Credit, Debit, PayPal)
- Navigation (Car, Bike, Walking routes)
- Logging (File, Console, Database)
💡 Bonus Tips
- Combine with the Factory Pattern to dynamically create strategies.
- Use in situations where algorithm selection happens at runtime.
✅ Summary Table
Element | Role |
---|---|
SortStrategy |
Defines the strategy interface |
BubbleSortStrategy , QuickSortStrategy , MergeSortStrategy
|
Concrete strategy classes |
SorterContext |
Manages and switches strategies |
Client |
Invokes strategy methods |
🚀 Wrapping Up Day 10!
This concludes the final day of our Design Patterns Series! 🎉 We’ve explored 10 key design patterns, complete with code samples, real-life examples, and explanations. 💻
You're now prepared to tackle design pattern questions in interviews and apply them in your coding projects.
Feel free to revisit this series whenever needed. Good luck with your coding journey, and let me know if you're ready to dive into more advanced topics! 🚀💯