Strategy mode
It defines the algorithm family and encapsulates them separately so that they can replace each other. This mode makes the change of algorithm not affect the users who use the algorithm.
Multiple if...else.. and switch statements can be avoided
Application scenario
1. If there are many classes in the system, and their differences only lie in their different behaviors.
2. A system needs to choose one of several algorithms dynamically.
For example, Jingdong now needs to promote sales and several preferential activities, so we can use the strategic model to write.
/** * @Author Darker * @Descrption Jingdong promotional activity preferential mode interface * @Date : Created in 13:54 2020-3-12 */ public interface JDactivity { //Promotion method /** * 1.Original price * 2.Cash return * 3.Coupon reduction * 4.Gift in kind * */ void activity(); } /** * @Author Darker * @Descrption * @Date : Created in 13:57 2020-3-12 */ public class EmptyActivity implements JDactivity{ @Override public void activity() { System.out.println("Original price"); } } /** * @Author Darker * @Descrption * @Date : Created in 13:59 2020-3-12 */ public class CashBackActivity implements JDactivity{ @Override public void activity() { System.out.println("Return cash directly for shopping and return cash to JD account"); } } /** * @Author Darker * @Descrption * @Date : Created in 13:57 2020-3-12 */ public class CouponsActivity implements JDactivity{ @Override public void activity() { System.out.println("Collect coupons and reduce the price of shopping"); } } /** * @Author Darker * @Descrption * @Date : Created in 14:00 2020-3-12 */ public class GiftActivity implements JDactivity { @Override public void activity() { System.out.println("Shopping gifts"); } } /** * @Author Darker * @Descrption Activity policy rules * @Date : Created in 14:02 2020-3-12 */ public class ActivityStrategy { //Regarding preferential activities as member variables, which seed of new is which kind of preferential JDactivity jDactivity; public ActivityStrategy(JDactivity jDactivity){ this.jDactivity = jDactivity; } public void execute(){ jDactivity.activity(); } }
Run and try
/** * @Author Darker * @Descrption * @Date : Created in 14:04 2020-3-12 */ public class StrategyTest { public static void main(String[] args) { //6.18 shopping activities ActivityStrategy activity618 = new ActivityStrategy(new CashBackActivity()); activity618.execute(); //Double 11 shopping discount ActivityStrategy activity1111 = new ActivityStrategy(new CouponsActivity()); activity1111.execute(); } }
This is the application of the simplest strategy mode. It defines an algorithm family (preference family), and dynamically selects an algorithm (preference).
But! But! But!!!
At the user call layer, you will find that you want if...else; For example, here's how to generate the preferential activities you want through the fields sent from the front end. Since the policy mode avoids if...esle.., it's still used now. Of course, it's not allowed to play and combine. If you see the following code, you can get rid of a simple factory mode. We can completely change it to a factory mode and use the factory to generate this strategy. By the way, we can change the factory to a factory mode Single case, but also improve efficiency.
So, let's code him
/** * @Author Darker * @Descrption * @Date : Created in 14:40 2020-3-12 */ public class ActivityStrategyFactory { //Constructor privatization private ActivityStrategyFactory(){}; //A single case of starving Han style private static ActivityStrategyFactory activityStrategyFactory = new ActivityStrategyFactory(); private static Map<String,JDactivity> iocMap = new HashMap<>(); static { iocMap.put(ActivityKey.COUPON,new CouponsActivity()); iocMap.put(ActivityKey.CASHBACK,new CashBackActivity()); iocMap.put(ActivityKey.GIFT,new GiftActivity()); } //No discount private static final ActivityStrategy NON_ACTIVITY_STRATEGY = new ActivityStrategy(new EmptyActivity()); //The only factory crossing in the whole world public static ActivityStrategyFactory getInstance(){ return activityStrategyFactory; } //Activities for the factory to generate corresponding policies public ActivityStrategy getActivityStrategy(String activity){ ActivityStrategy activityStrategy = new ActivityStrategy(iocMap.get(activity)); return activityStrategy == null ? NON_ACTIVITY_STRATEGY:activityStrategy; } //Activity string, conventions > configuration private interface ActivityKey{ String COUPON = "COUPON"; String CASHBACK = "CASHBACK"; String GIFT = "GIFT"; } }
Run it
/** * @Author Darker * @Descrption * @Date : Created in 14:04 2020-3-12 */ public class StrategyTest { public static void main(String[] args) { //Active key from the front end String activityKey = "CASHBACK"; //Generate policy factory ActivityStrategyFactory strategyFactory = ActivityStrategyFactory.getInstance(); ActivityStrategy activityStrategy = strategyFactory.getActivityStrategy(activityKey); activityStrategy.execute(); } }
You see it's very friendly to client calls. No, when we add activities, we just need to add a little configuration field. It's also fast to change.
Let's take a look at this class diagram:
So it's clear that we have four preferential strategies, which are generated by activity strategies and produced by factories.
Isn't it addictive? Let's recreate a function often used in daily life, mobile payment, a very classic strategy mode.
/** * @Author Darker * @Descrption Payment abstract class, including public judgment logic * @Date : Created in 16:12 2020-3-12 */ public abstract class Paymet { public abstract String getKeyName(); //Check the balance protected abstract double queryBalance(String uid); //Public payment logic public MsgResult pay(String uid,double amount){ if(queryBalance(uid)<amount){ return new MsgResult(500,"Failure to pay","Sorry, your credit is running low"); }else{ return new MsgResult(200,"Successful payment","Payment amount"+amount); } } } /** * @Author Darker * @Descrption * @Date : Created in 16:11 2020-3-12 */ public class Alipay extends Paymet{ @Override public String getKeyName() { return "Alipay"; } @Override protected double queryBalance(String uid) { return 250; } } /** * @Author Darker * @Descrption * @Date : Created in 16:16 2020-3-12 */ public class JDpay extends Paymet { @Override public String getKeyName() { return "Jingdong ious"; } @Override protected double queryBalance(String uid) { return 500; } } /** * @Author Darker * @Descrption * @Date : Created in 16:18 2020-3-12 */ public class WechatPay extends Paymet { @Override public String getKeyName() { return "WeChat payment"; } @Override protected double queryBalance(String uid) { return 700; } } /** * @Author Darker * @Descrption Order * @Date : Created in 15:45 2020-3-12 */ @Data @AllArgsConstructor public class Order { private String uid; private String orderId; private Double amount; public MsgResult pay(String payKey){ Paymet paymet = PayStrategy.getInstance(payKey); MsgResult result = paymet.pay(orderId, amount); return result; } } /** * @Author Darker * @Descrption Return package class * @Date : Created in 16:07 2020-3-12 */ @Data @AllArgsConstructor public class MsgResult { private int code; private Object data; private String msg; @Override public String toString() { return "Payment status:[" + code +"]," + msg +",transaction details"+ data; } } /** * @Author Darker * @Descrption Payment strategy * @Date : Created in 16:25 2020-3-12 */ public class PayStrategy { public static final String ALI_PAY = "Alipay"; public static final String JD_PAY = "Jdpay"; public static final String WECHAT_PAY = "Wechatpay"; public static final String DEFAULT_PAY = ALI_PAY; private static Map<String, Paymet> payStrategy =new HashMap<>(); static { payStrategy.put(ALI_PAY,new Alipay()); payStrategy.put(JD_PAY,new JDpay()); payStrategy.put(WECHAT_PAY,new WechatPay()); } public static Paymet getInstance(String payKey){ Paymet paymet = payStrategy.get(payKey) ; return paymet == null ? payStrategy.get(DEFAULT_PAY):paymet; } } /** * @Author Darker * @Descrption test * @Date : Created in 16:21 2020-3-12 */ public class payStrategyTest { public static void main(String[] args) { String payKey = "Jdpay"; String payKey2 = "Wechatpay"; //User submitted an order Order order = new Order("1", "2020031200000000", 570.00); //User chooses payment method, Jingdong Baitiao MsgResult result = order.pay(payKey); System.out.println(result); //Payment method selected by users, wechat payment MsgResult result2 = order.pay(payKey2); System.out.println(result2); } }
Let's see if this is the way we actually pay.
OK, finally, let's talk about where jdk uses the strategy mode. The answer is Comparator, Comparator. We often use Comparator to sort. There are many algorithms in this Comparator. We can choose our own preferred strategy to sort, which is very classic.
Similarly, the policy pattern is also used in spring. When initializing a class, it will choose whether to use jdk or cglib.
Conclusion:
Advantage:
1. The strategy mode conforms to the opening and closing principle
2. Avoid using multiple conditional transfer statements, such as if...else
3. Using policy mode can improve the security and secrecy of the algorithm
Disadvantages:
1. The client must know all policies and decide which policy class to use.
2. A lot of policy classes will be generated in the code. Do you want to add maintenance.