The Strategy Pattern is a behavioral design pattern that turns a set of behaviors into objects and makes them interchangeable inside an original context object.
It allows you to switch the "strategy" or "algorithm" your code uses at runtime without changing the class that uses it.
[Image of Strategy design pattern diagram]
The Problem
Imagine you are building a Navigation App. Your app calculates the time it takes to get from Point A to Point B.
- Initially, you only support Driving.
- Later, you add Walking.
- Then, you add Public Transport.
If you put all this logic into one Navigator class, your buildRoute method becomes a giant mess of if-else statements. Every time you add a new travel mode (like "Cycling"), you have to open the main class and risk breaking the code for the other modes.
The Solution: The "Plugin" Approach
Instead of one class doing everything, you define a common interface for all route-building algorithms. Each travel mode becomes its own class (a "Strategy"). The Navigator class simply holds a reference to a RouteStrategy and delegates the work to it.
Step-by-Step Java Implementation
1. The Strategy Interface
This defines the method that all specific strategies must implement.
// RouteStrategy.java
public interface RouteStrategy {
void buildRoute(String start, String end);
}
2. Concrete Strategies
Each class implements a specific version of the algorithm.
// DrivingStrategy.java
class DrivingStrategy implements RouteStrategy {
public void buildRoute(String start, String end) {
System.out.println("Calculating driving route: Avoiding tolls and heavy traffic.");
}
}
// WalkingStrategy.java
class WalkingStrategy implements RouteStrategy {
public void buildRoute(String start, String end) {
System.out.println("Calculating walking route: Using sidewalks and pedestrian paths.");
}
}
3. The Context
The class that the user interacts with. It doesn't know how the route is built; it just knows it has a strategy to do it.
// Navigator.java
public class Navigator {
private RouteStrategy strategy;
// We can set the strategy at runtime
public void setStrategy(RouteStrategy strategy) {
this.strategy = strategy;
}
public void executeRoute(String start, String end) {
strategy.buildRoute(start, end);
}
}
Full Code for Testing
// Save as StrategyTest.java
// 1. The Strategy Interface
interface PaymentStrategy {
void pay(int amount);
}
// 2. Concrete Strategy: Credit Card
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String card) { this.cardNumber = card; }
@Override
public void pay(int amount) {
System.out.println("Paid $" + amount + " using Credit Card [" + cardNumber + "]");
}
}
// 2. Concrete Strategy: PayPal
class PayPalPayment implements PaymentStrategy {
private String email;
public PayPalPayment(String email) { this.email = email; }
@Override
public void pay(int amount) {
System.out.println("Paid $" + amount + " using PayPal account: " + email);
}
}
// 3. The Context: Shopping Cart
class ShoppingCart {
private PaymentStrategy paymentMethod;
public void setPaymentMethod(PaymentStrategy method) {
this.paymentMethod = method;
}
public void checkout(int total) {
if (paymentMethod == null) {
System.out.println("Please select a payment method!");
} else {
paymentMethod.pay(total);
}
}
}
// 4. Test
public class StrategyTest {
public static void main(String[] args) {
System.out.println("--- Strategy Pattern: Checkout Test ---\n");
ShoppingCart cart = new ShoppingCart();
// User chooses PayPal
cart.setPaymentMethod(new PayPalPayment("ahmed.codes@example.com"));
cart.checkout(150);
// User decides to switch to Credit Card at the last second
System.out.println("\n[System] User switched payment method...");
cart.setPaymentMethod(new CreditCardPayment("1234-5678-9012"));
cart.checkout(150);
System.out.println("\n--- Transaction Complete ---");
}
}
Why use Strategy?
- Open/Closed Principle: You can add new strategies (like
CryptoPayment) without changing theShoppingCartclass. - Runtime Switching: You can swap the behavior of an object while the program is running.
- Isolation: You isolate the complex math or logic of an algorithm from the rest of the user interface code.
Real-World Example
- Sorting Algorithms: Java's
Collections.sort()takes aComparatoras a strategy. You can pass a differentComparatorto sort by name, date, or size without changing the sort method itself. - Compression: A file archiver might use different strategies for
Zip,Rar, or7zcompression.