This is the fourth day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021
This article is excerpted from This is How Design Patterns should Be Learned
1. Use strategy mode to select promotion and discount schemes
As we all know, the architecture courses of Golpo College often have preferential activities. There are many possible preferential strategies, such as coupon deduction, cash back promotion, group discount, etc. To simulate this, start by creating an abstract PromotionStrategy for a PromotionStrategy.
/** * Created by Tom. */
public interface IPromotionStrategy {
void doPromotion(a);
}
Copy the code
Then create the class of coupon deduction strategy CouponStrategy, CashbackStrategy, GroupbuyStrategy and EmptyStrategy respectively. The code for the CouponStrategy class is as follows.
public class CouponStrategy implements IPromotionStrategy {
public void doPromotion(a) {
System.out.println("Use coupons to offset"); }}Copy the code
The code for the CashbackStrategy class is as follows.
public class CashbackStrategy implements IPromotionStrategy {
public void doPromotion(a) {
System.out.println("Cash back, direct payment to alipay account"); }}Copy the code
The GroupbuyStrategy class is coded as follows.
public class GroupbuyStrategy implements IPromotionStrategy {
public void doPromotion(a) {
System.out.println("Discounts for groups of five."); }}Copy the code
The code for the EmptyStrategy class is as follows.
public class EmptyStrategy implements IPromotionStrategy {
public void doPromotion(a) {
System.out.println("No discount"); }}Copy the code
Next, create the promotion scheme PromotionActivity class.
public class PromotionActivity {
private IPromotionStrategy strategy;
public PromotionActivity(IPromotionStrategy strategy) {
this.strategy = strategy;
}
public void execute(a){ strategy.doPromotion(); }}Copy the code
Finally write the client test code.
public static void main(String[] args) {
PromotionActivity activity618 = new PromotionActivity(new CouponStrategy());
PromotionActivity activity1111 = new PromotionActivity(new CashbackStrategy());
activity618.execute();
activity1111.execute();
}
Copy the code
At this point, you may find that the above client-side test code is not practical if you put it into a real business scenario. Because when we do activities, we often choose promotion strategies dynamically according to different needs, and do not implement multiple offers at one time. So this is what code is usually written.
public static void main(String[] args) {
PromotionActivity promotionActivity = null;
String promotionKey = "COUPON";
if(StringUtils.equals(promotionKey,"COUPON")){
promotionActivity = new PromotionActivity(new CouponStrategy());
}else if(StringUtils.equals(promotionKey,"CASHBACK")){
promotionActivity = new PromotionActivity(new CashbackStrategy());
}/ /...
promotionActivity.execute();
}
Copy the code
After this transformation, the code meets the business requirements, and customers can choose different preferential strategies according to their needs. However, after a period of business accumulation, promotional activities will be more and more. As a result, programmers start working overtime, pulling all-nighters to change their code before each event, doing repeated tests, and judgment logic can become increasingly complex. At this point, we need to think about whether the code needs to be refactored. Looking back at the design patterns we’ve learned, how can we optimize this code? In fact, you can combine the singleton pattern with the simple factory pattern to create the PromotionStrategyFactory class.
public class PromotionStrategyFacory {
private static Map<String,IPromotionStrategy> PROMOTIONS = new HashMap<String, IPromotionStrategy>();
static {
PROMOTIONS.put(PromotionKey.COUPON,new CouponStrategy());
PROMOTIONS.put(PromotionKey.CASHBACK,new CashbackStrategy());
PROMOTIONS.put(PromotionKey.GROUPBUY,new GroupbuyStrategy());
}
private static final IPromotionStrategy EMPTY = new EmptyStrategy();
private PromotionStrategyFacory(a){}
public static IPromotionStrategy getPromotionStrategy(String promotionKey){
IPromotionStrategy strategy = PROMOTIONS.get(promotionKey);
return strategy == null ? EMPTY : strategy;
}
private interface PromotionKey{
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
String GROUPBUY = "GROUPBUY";
}
public static Set<String> getPromotionKeys(a){
returnPROMOTIONS.keySet(); }}Copy the code
At this point, the client test code is as follows.
public static void main(String[] args) {
PromotionStrategyFacory.getPromotionKeys();
String promotionKey = "COUPON";
IPromotionStrategy promotionStrategy = PromotionStrategyFacory.getPromotionStrategy (promotionKey);
promotionStrategy.doPromotion();
}
Copy the code
After code optimization, programmer maintenance becomes easier. Each new activity does not affect the original code logic.
2 Use the policy mode to reconstruct the payment mode selection scenario
To deepen our understanding of strategic patterns, let’s take another example. I believe that all of you have used Alipay, wechat Pay, UnionPay and JINGdong Paitiao. A common application scenario is that you will be prompted to select a payment method when placing an order and paying. If the user does not select the payment method, the system will default to the recommended payment method for settlement. Looking at the class diagram shown below, we use the policy pattern to simulate this business scenario.
First, create the Payment abstract class to define the Payment specification and Payment logic as follows.
import com.tom.pattern.strategy.pay.PayState;
/** * Created by Tom. */
public abstract class Payment {
public abstract String getName(a);
// Generic logic is implemented in abstract classes
public MsgResult pay(String uid, double amount){
// Is the balance sufficient
if(queryBalance(uid) < amount){
return new MsgResult(500."Payment failure"."Insufficient balance");
}
return new MsgResult(200."Payment successful"."Amount paid" + amount);
}
protected abstract double queryBalance(String uid);
}
Copy the code
Then create specific payment methods respectively. The code of AliPay is as follows.
public class AliPay extends Payment {
public String getName(a) {
return "Alipay";
}
protected double queryBalance(String uid) {
return 900; }}Copy the code
The code of jd Baitiao JDPay class is as follows.
public class JDPay extends Payment {
public String getName(a) {
return Jingdong IOUS;
}
protected double queryBalance(String uid) {
return 500; }}Copy the code
The code of WechatPay is as follows.
public class WechatPay extends Payment {
public String getName(a) {
return "Wechat Pay";
}
protected double queryBalance(String uid) {
return 263; }}Copy the code
The code for the UnionPay class is as follows.
public class UnionPay extends Payment {
public String getName(a) {
return "Union Pay";
}
protected double queryBalance(String uid) {
return 120; }}Copy the code
Next, create the payment status wrapper class MsgResult.
/** Created by Tom. */
public class MsgResult {
private int code;
private Object data;
private String msg;
public MsgResult(int code, String msg, Object data) {
this.code = code;
this.data = data;
this.msg = msg;
}
@Override
public String toString(a) {
return "MsgResult{" +
"code=" + code +
", data=" + data +
", msg='" + msg + '\' ' +
'} '; }}Copy the code
Create the Payment Policy Management class.
import java.util.HashMap;
import java.util.Map;
/** * Created by Tom. */
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 UNION_PAY = "UnionPay";
public static final String DEFAULT_PAY = ALI_PAY;
private static Map<String,Payment> strategy = new HashMap<String,Payment>();
static {
strategy.put(ALI_PAY,new AliPay());
strategy.put(JD_PAY,new JDPay());
strategy.put(WECHAT_PAY,new WechatPay());
strategy.put(UNION_PAY,new UnionPay());
}
public static Payment get(String payKey){
if(! strategy.containsKey(payKey)){return strategy.get(DEFAULT_PAY);
}
returnstrategy.get(payKey); }}Copy the code
Create the Order Order class.
import com.tom.pattern.strategy.pay.payport.PayStrategy;
import com.tom.pattern.strategy.pay.payport.Payment;
/** * Created by Tom. */
public class Order {
private String uid;
private String orderId;
private double amount;
public Order(String uid, String orderId, double amount) {
this.uid = uid;
this.orderId = orderId;
this.amount = amount;
}
public MsgResult pay(a){
return pay(PayStrategy.DEFAULT_PAY);
}
public MsgResult pay(String payKey){
Payment payment = PayStrategy.get(payKey);
System.out.println("Welcome to use" + payment.getName());
System.out.println("The transaction amount is + amount + ", start the deduction.");
returnpayment.pay(uid,amount); }}Copy the code
Finally write the client test code.
public static void main(String[] args) {
Order order = new Order("1"."2020031401000323".324.5);
System.out.println(order.pay(PayStrategy.ALI_PAY));
}
Copy the code
The running result is shown in the figure below.
Through common business scenarios, I hope you can have a deeper understanding of the strategy pattern.
Pay attention to “Tom play architecture” reply to “design pattern” can obtain the complete source code.
Tom play architecture: 30 real cases of design patterns (attached source code), the challenge of annual salary 60W is not a dream
This article is “Tom play structure” original, reproduced please indicate the source. Technology is to share, I share my happiness! If this article is helpful to you, welcome to follow and like; If you have any suggestions can also leave a comment or private letter, your support is my motivation to adhere to the creation. Pay attention to “Tom bomb architecture” for more technical dry goods!