Tip #17: (Don't) Learn The Strategy Pattern
Strategy it's a behavioral pattern, so you will only use this concept when you need to change the behavior of your code. (If you are not doing this, you are probably using a Decorator).
Do you really need to implement interfaces and classes for each behavior?
You are a developer using new Java features, so you have enhaced switch, pattern matching, functions. If you don’t know about it, maybe you can just create an enum with possible values and create functions?
See this Java implementation for one of the best sites about design patterns.
We have a lot of issues there, like setTotalCost is adding not seting, or you need a paymentMethod to create an order, just to call paymentDetails…
But let’s see what we can do to make it better:
Let’s make processOrder receive an enum PayStrategy and make the strategy pattern using functions:
Function<Integer,Boolean> payStrategyConsumer;
public Boolean processOrder(PayStrategy payStrategy) {
payStrategyConsumer = switch (payStrategy) {
case PALPAY -> PaymentDetails::payPalPay;
case CREDIT_CARD -> PaymentDetails::payCreditCard;
};
return payStrategyConsumer.apply(totalCost);
}
Now, we will receive a totalCost ( int) and return boolean. Methods are now in PaymentDetails, and not in each class. It’s easier to reuse payment method code:
public class PaymentDetails {
private static BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));
//create one method for each payment method to display payment details
public static boolean payPalPay(int paymentAmount) {
try {
System.out.print("Enter the user's email: ");
String email = READER.readLine();
System.out.print("Enter the password: ");
String password = READER.readLine();
//validate
System.out.println("Paying " + paymentAmount + " using PayPal.");
return true;
} catch (IOException ex) {
ex.printStackTrace();
}
return false;
}
public static boolean payCreditCard(int paymentAmount) {
try {
System.out.print("Enter the card number: ");
String number = READER.readLine();
System.out.print("Enter the card expiration date 'mm/yy': ");
String date = READER.readLine();
System.out.print("Enter the CVV code: ");
String cvv = READER.readLine();
var card = new CreditCard(number, date, cvv);
// Validate credit card number...
System.out.println("Paying " + paymentAmount + " using Credit Card.");
card.setAmount(card.getAmount() - paymentAmount);
return true;
} catch (IOException ex) {
ex.printStackTrace();
}
return false;
}
}
Now we have a compiler error if we add a new enum value. We have a simple code with some functions that does exactly what the previous strategy pattern with interfaces and classes did.
That’s it!
Happy coding!