Strategy mode
Application scenarios
JD.com, Tmall Double Eleven, Valentine's Day merchandise sales, various merchandise have different promotions
- Full reduction: Full 200 minus 50
- Every full deduction: every full 100 minus 10
- Discount: 20% off for two items, 30% off for three items
- Quantity minus: full three pieces minus the lowest price one
Customers can choose several of them to chop their hands when placing an order. How can the back-end deal with the calculation of the amount flexibly? There may be more promotions on different festivals in the future. How to calculate the amount of the order?
Simple implementation example
public class OrderService {
public Order OrderPrices(Order order, String promotion) {
if (promotion.equals("promotion-1")) {
//计算金额
} else if (promotion.equals("promotion-2")) {
//计算金额
}
switch (promotion) {
case "promotion-1" :
//计算金额
break;
case "promotion-2" :
//计算金额
break;
}
return order;
}
}
There is no problem with using if else or switch case as mentioned above, but there will be many kinds of promotional activities. In this case, there will be a lot of content in if else or switch case, so how to improve it
may be thought of, each The promotion method will be better if it is taken out separately, based on the design principle of this method: the principle of single responsibility
public class OrderService {
public Order OrderPrices(Order order, String promotion) {
if (promotion.equals("promotion-1")) {
calPromotion1(order);
} else if (promotion.equals("promotion-2")) {
calPromotion2(order);
}
switch (promotion) {
case "promotion-1" :
calPromotion1(order);
break;
case "promotion-2" :
calPromotion2(order);
break;
}
return order;
}
public Order calPromotion1(Order order) {
return order;
}
public Order calPromotion2(Order order) {
return order;
}
}
Although the above improvement is better, the promotion activities are constantly changing, and the OrderService class needs to be modified as soon as the change is made. The OrderService class is about orders and hopes to be changed less. What is constantly changing is the
analysis of the promotion algorithm . What has changed here is a different algorithm for the same behavior, so improve it again
Improve the code
To implement different algorithms for the same behavior, we can use interfaces to define behaviors, and different algorithms to implement interfaces separately.
Design principle: closed for modification, open for extension
public interface PromotionAlgorithm {
Order promotionAlgorithm(Order order);
}
public class PromotionAlgorithm1 implements PromotionAlgorithm {
@Override
public Order promotionAlgorithm(Order order) {
System.out.println("满200减50");
return order;
}
}
public class PromotionAlgorithm2 implements PromotionAlgorithm {
@Override
public Order promotionAlgorithm(Order order) {
System.out.println("满2件打8折");
return order;
}
}
public class OrderService {
public Order OrderPrices(Order order, String promotion) {
if (promotion.equals("promotion-1")) {
return new PromotionAlgorithm1().promotionAlgorithm(order);
} else if (promotion.equals("promotion-2")) {
return new PromotionAlgorithm2().promotionAlgorithm(order);
}
switch (promotion) {
case "promotion-1" :
return new PromotionAlgorithm1().promotionAlgorithm(order);
case "promotion-2" :
return new PromotionAlgorithm2().promotionAlgorithm(order);
}
return order;
}
}
Implement each promotion algorithm separately and then use it. This is the application
class diagram of the strategy pattern :
Strategy mode
definition
The strategy mode defines a series of algorithms, and encapsulates each algorithm, and allows them to be replaced with each other, so that the algorithm can change independently of the users who use it.
intention
Define a series of algorithms, encapsulate them one by one, and make them interchangeable
Mainly solve the problem
In the case of multiple similar algorithms, the use of if...else is complicated and difficult to maintain
When to use
A system has many classes, and what distinguishes them is their direct behavior
Pros and cons
advantage:
1: Various algorithms can be switched at will
2: Can avoid the trouble caused by the use of multiple judgments
3: Good scalability
Disadvantages:
1: There are more strategy classes.
2: All strategy classes need to be exposed to the outside world.
Let’s look at the class diagram below:
the roles involved:
- Context role: holding a reference to the Stratogy class
- Abstract strategy (Strategy) role: This is an abstract role, usually implemented by an interface or abstract class, this role gives all the interfaces required by the specific strategy class
- Specific strategy (ConcreteStartegy) role: packaging related algorithms or behaviors
Context class:
public class Context {
private Strategy strategy;
/** 策略方法 */
public void contextInterface() {
strategy.strategyInterface();
}
}
Strategy class:
public interface Strategy {
/** 策略方法 */
void strategyInterface();
}
ConcreteStrategy class:
public class ConcreteStrategy implements Strategy{
/** 策略方法 */
@Override
public void strategyInterface() {
//do something
}
}
Zhuge Liang's Tips
Back then, when Zhao Yun protected Liu Bei from entering the country of Wu to marry a beautiful woman, Zhuge Liang gave him three tips with three tricks, and asked Zhao Yun to act according to the situation. These three tips and tricks are in line with the strategy mode. It seems that Zhuge Liang is not the initiator of the strategy mode but also the original practitioner. The following is a small example: the
tips and tricks interface:
public interface SeminalVesicle {
/** 按计行事 */
String tricks();
}
Do according to plan implementation class:
public class BackDoor implements SeminalVesicle {
/** 按计行事 */
@Override
public String tricks() {
return "走乔国老的后门";
}
}
public class GoBack implements SeminalVesicle {
/** 按计行事 */
@Override
public String tricks() {
return "骗刘备回去";
}
}
public class Retreat implements SeminalVesicle {
/** 按计行事 */
@Override
public String tricks() {
return "请孙夫人退兵";
}
}
Zhao Yun class:
public class ZhaoYun {
private SeminalVesicle seminalVesicle;
public ZhaoYun(SeminalVesicle seminalVesicle) {
this.seminalVesicle = seminalVesicle;
}
/** 按计行事 */
public String act() {
return seminalVesicle.tricks();
}
}
Test category:
public class Test {
public static void main(String[] args) {
ZhaoYun zhaoYun = new ZhaoYun(new Retreat());
System.out.println("赵云按计行事");
System.out.println(zhaoYun.act());
}
}
Class diagram: It
should be noted that if there are more strategies, almost more than 4, you need to consider using mixed mode to avoid strategy expansion