Usage examples: The Strategy pattern is very common in Java code. It’s often used in various frameworks to provide users a way to change the behavior of a class without extending it.
Java 8 brought the support of lambda functions, which can serve as simpler alternatives to the Strategy pattern.
Here some examples of Strategy in core Java libraries:
javax.servlet.http.HttpServlet: service() method, plus all of the doXXX() methods that accept HttpServletRequest and HttpServletResponse objects as arguments.
Identification: Strategy pattern can be recognized by a method that lets a nested object do the actual work, as well as a setter that allows replacing that object with a different one.
Payment method in an e-commerce app
In this example, the Strategy pattern is used to implement the various payment methods in an e-commerce application. After selecting a product to purchase, a customer picks a payment method: either Paypal or credit card.
Concrete strategies not only perform the actual payment but also alter the behavior of the checkout form, providing appropriate fields to record payment details.
strategies
strategies/PayStrategy.java: Common interface of payment methods
packagerefactoring_guru.strategy.example.strategies;/** * Common interface for all strategies. */publicinterfacePayStrategy {booleanpay(int paymentAmount);voidcollectPaymentDetails();}
packagerefactoring_guru.strategy.example.order;importrefactoring_guru.strategy.example.strategies.PayStrategy;/** * Order class. Doesn't know the concrete payment method (strategy) user has * picked. It uses common strategy interface to delegate collecting payment data * to strategy object. It can be used to save order to database. */publicclassOrder {privateint totalCost =0;privateboolean isClosed =false;publicvoidprocessOrder(PayStrategy strategy) {strategy.collectPaymentDetails();// Here we could collect and store payment data from the strategy. }publicvoidsetTotalCost(int cost) {this.totalCost+= cost; }publicintgetTotalCost() {return totalCost; }publicbooleanisClosed() {return isClosed; }publicvoidsetClosed() { isClosed =true; }}
Demo.java: Client code
packagerefactoring_guru.strategy.example;importrefactoring_guru.strategy.example.order.Order;importrefactoring_guru.strategy.example.strategies.PayByCreditCard;importrefactoring_guru.strategy.example.strategies.PayByPayPal;importrefactoring_guru.strategy.example.strategies.PayStrategy;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.util.HashMap;importjava.util.Map;/** * World first console e-commerce application. */publicclassDemo {privatestaticMap<Integer,Integer> priceOnProducts =newHashMap<>();privatestaticBufferedReader reader =newBufferedReader(new InputStreamReader(System.in));privatestaticOrder order =newOrder();privatestaticPayStrategy strategy;static {priceOnProducts.put(1,2200);priceOnProducts.put(2,1850);priceOnProducts.put(3,1100);priceOnProducts.put(4,890); }publicstaticvoidmain(String[] args) throwsIOException {while (!order.isClosed()) {int cost;String continueChoice;do {System.out.print("Please, select a product:"+"\n"+"1 - Mother board"+"\n"+"2 - CPU"+"\n"+"3 - HDD"+"\n"+"4 - Memory"+"\n");int choice =Integer.parseInt(reader.readLine()); cost =priceOnProducts.get(choice);System.out.print("Count: ");int count =Integer.parseInt(reader.readLine());order.setTotalCost(cost * count);System.out.print("Do you wish to continue selecting products? Y/N: "); continueChoice =reader.readLine(); } while (continueChoice.equalsIgnoreCase("Y"));if (strategy ==null) {System.out.println("Please, select a payment method:"+"\n"+"1 - PalPay"+"\n"+"2 - Credit Card");String paymentMethod =reader.readLine();// Client creates different strategies based on input from user,// application configuration, etc.if (paymentMethod.equals("1")) { strategy =newPayByPayPal(); } else { strategy =newPayByCreditCard(); } }// Order object delegates gathering payment data to strategy object,// since only strategies know what data they need to process a// payment.order.processOrder(strategy);System.out.print("Pay "+order.getTotalCost() +" units or Continue shopping? P/C: ");String proceed =reader.readLine();if (proceed.equalsIgnoreCase("P")) {// Finally, strategy handles the payment.if (strategy.pay(order.getTotalCost())) {System.out.println("Payment has been successful."); } else {System.out.println("FAIL! Please, check your data."); }order.setClosed(); } } }}
OutputDemo.txt: Execution result
Please, select a product:
1 - Mother board
2 - CPU
3 - HDD
4 - Memory
1
Count: 2
Do you wish to continue selecting products? Y/N: y
Please, select a product:
1 - Mother board
2 - CPU
3 - HDD
4 - Memory
2
Count: 1
Do you wish to continue selecting products? Y/N: n
Please, select a payment method:
1 - PalPay
2 - Credit Card
1
Enter the user's email: user@example.com
Enter the password: qwerty
Wrong email or password!
Enter user email: amanda@ya.com
Enter password: amanda1985
Data verification has been successful.
Pay 6250 units or Continue shopping? P/C: p
Paying 6250 using PayPal.
Payment has been successful.