Strategy is a behavioral design pattern that turns a set of behaviors into objects and makes them interchangeable inside original context object.
Lets take an example of payment methods ā
Suppose we have to create an application, where a user can pay using either a card or UPI.
A general code for doing above can be written like below ā
if (paymentMethod.equals("1")) {
PayPal p = new PayPal();
p.pay(amount);
} else if (paymentMethod.equals("2")) {
CreditCard c = new CreditCard();
c.pay(amount);
} else if (paymentMethod.equals("3")) {
GooglePay g = new GooglePay();
g.pay(amount);
}
Here, we have created 3 classes for each payment type. And the above code is being called from a resource layer or business layer.
Now, if we recall the SOLID principles, we can easily see the violation of Open/Closed principle. Because later if more methods are added, weāll need to change the code in client class. But if we do following
if (paymentMethod.equals("1")) {
PaymentStrategy p = new PayPal();
p.pay(amount);
} else if (paymentMethod.equals("2")) {
PaymentStrategy c = new CreditCard();
c.pay(amount);
} else if (paymentMethod.equals("3")) {
PaymentStrategy g = new GooglePay();
g.pay(amount);
}
where PaymentStrategy is an interface and all the strategy classes extend this. Does this solve the problem. Well, not entirely. Because we still have Open/Closed principle being violated due to addition of a new if else clause and imports for that strategy too.
So what would be the right way to do it?
Lets find out.
public class PaymentStrategyFactory {
private static final Map strategies = Map.of(
"paypal", new PayByPayPal(),
"creditcard", new PayByCreditCard(),
"googlepay", new PayByGooglePay()
);
public static PayStrategy getStrategy(String method) {
return strategies.get(method.toLowerCase());
}
}
Here, we have a factory entirely designed to take care of the strategies.
The map is of types String, PayStrategy. And all the strategies implements this interface. So we dont need to define the specific strategy class. Factory would take care of all of them.
getStrategy() method is used to fetch the instance of the strategy that is called from the client code. So client code would look like following ā
PayStrategy strategy = PaymentStrategyFactory.getStrategy(paymentMethod);
strategy.pay();
here paymentMethod could contain āpaypalā or ācreditCardā or āgooglePayā.
So we donāt need to change anything in client code.