Imagine you are building an e-commerce platform, and you need to handle multiple payment methods like credit cards, PayPal, and bank transfers. Each method has its own processing logic, but you want to keep your code flexible and maintainable.
How do you manage these different payment methods without cluttering your code with conditionals? The Strategy Design Pattern is the solution, allowing you to define a family of algorithms, encapsulate each one, and make them interchangeable.
What is the Strategy Pattern?
The Strategy Pattern is a behavioral design pattern that enables you to define a set of algorithms, encapsulate them in separate classes, and switch between them dynamically. This makes your code more modular, easier to extend, and avoids hard-coded logic.
Code Example
// Strategy Interface
interface PaymentStrategy {
boolean processPayment(double amount);
}
// Concrete Strategy: Credit Card
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public boolean processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
// Simulate card validation and API call
return true;
}
}
// Concrete Strategy: PayPal
class PayPalPayment implements PaymentStrategy {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public boolean processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
// Simulate PayPal API call
return true;
}
}
// Context Class
class PaymentProcessor {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public boolean process(double amount) {
if (paymentStrategy == null) {
throw new IllegalStateException("Payment strategy not set");
}
return paymentStrategy.processPayment(amount);
}
}
// Usage Example
public class Main {
public static void main(String[] args) {
PaymentProcessor processor = new PaymentProcessor();
// Paying with Credit Card
processor.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456"));
processor.process(100.0);
// Switching to PayPal
processor.setPaymentStrategy(new PayPalPayment("user@example.com"));
processor.process(50.0);
}
}
- The PaymentStrategy interface defines the contract for all payment methods.
- Each concrete strategy (CreditCardPayment, PayPalPayment) encapsulates its own logic.
- The PaymentProcessor context class delegates the payment processing to the current strategy.
- At runtime, you can swap strategies (e.g., switch from Credit Card to PayPal) without modifying the PaymentProcessor.
Benefits
- Flexibility: Add new payment methods by creating new strategy classes without changing existing code.
- Maintainability: Each payment method is encapsulated, reducing code complexity.
- Reusability: Strategies can be reused across different contexts.
The Strategy Pattern solves the problem of handling multiple payment methods by making them interchangeable and encapsulated. By using this pattern, your e-commerce platform can easily support new payment methods, keeping your codebase clean and scalable.