写点什么

使用策略模式重构电商折扣和支付场景

用户头像
Tom弹架构
关注
发布于: 2021 年 11 月 05 日

本文节选自《设计模式就该这样学》

1 使用策略模式实现促销优惠方案选择

大家都知道,咕泡学院的架构师课程经常会有优惠活动,优惠策略有很多种可能,如领取优惠券抵扣、返现促销、拼团优惠等。下面用代码来模拟,首先创建一个促销策略的抽象 PromotionStrategy。



/** * 促销策略抽象 * Created by Tom. */public interface IPromotionStrategy { void doPromotion();}
复制代码


然后分别创建优惠券抵扣策略 CouponStrategy 类、返现促销策略 CashbackStrategy 类、拼团优惠策略 GroupbuyStrategy 类和无优惠策略 EmptyStrategy 类。CouponStrategy 类的代码如下。



public class CouponStrategy implements IPromotionStrategy { public void doPromotion() { System.out.println("使用优惠券抵扣"); }}
复制代码


CashbackStrategy 类的代码如下。



public class CashbackStrategy implements IPromotionStrategy { public void doPromotion() { System.out.println("返现,直接打款到支付宝账号"); }}
复制代码


GroupbuyStrategy 类的代码如下。



public class GroupbuyStrategy implements IPromotionStrategy { public void doPromotion() { System.out.println("5人成团,可以优惠"); }}
复制代码


EmptyStrategy 类的代码如下。



public class EmptyStrategy implements IPromotionStrategy { public void doPromotion() { System.out.println("无优惠"); }}
复制代码


接着创建促销活动方案 PromotionActivity 类。



public class PromotionActivity { private IPromotionStrategy strategy;
public PromotionActivity(IPromotionStrategy strategy) { this.strategy = strategy; }
public void execute(){ strategy.doPromotion(); }}
复制代码


最后编写客户端测试代码。



public static void main(String[] args) { PromotionActivity activity618 = new PromotionActivity(new CouponStrategy()); PromotionActivity activity1111 = new PromotionActivity(new CashbackStrategy());
activity618.execute(); activity1111.execute();}
复制代码


此时,小伙伴们会发现,如果把上面这段客户端测试代码放到实际的业务场景中,其实并不实用。因为我们做活动的时候往往要根据不同的需求对促销策略进行动态选择,并不会一次性执行多种优惠。所以代码通常会这样写。



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();}
复制代码


这样改造之后,代码满足了业务需求,客户可根据自己的需求选择不同的优惠策略。但是,经过一段时间的业务积累,促销活动会越来越多。于是,程序员就开始经常加班,每次上活动之前都要通宵改代码,而且要做重复测试,判断逻辑可能也会变得越来越复杂。此时,我们要思考代码是否需要重构。回顾之前学过的设计模式,我们应该如何来优化这段代码呢?其实,可以结合单例模式和简单工厂模式,创建 PromotionStrategyFactory 类。



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(){}
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(){ return PROMOTIONS.keySet(); }}
复制代码


这时候,客户端测试代码如下。



public static void main(String[] args) { PromotionStrategyFacory.getPromotionKeys(); String promotionKey = "COUPON";
IPromotionStrategy promotionStrategy = PromotionStrategyFacory.getPromotionStrategy (promotionKey); promotionStrategy.doPromotion();}
复制代码


代码优化之后,程序员的维护工作也变得轻松了。每次上新活动都不影响原来的代码逻辑。

2 使用策略模式重构支付方式选择场景

为了加深对策略模式的理解,我们再举一个案例。相信小伙伴们都用过支付宝、微信支付、银联支付及京东白条,一个常见的应用场景就是大家在下单支付时会提示选择支付方式,如果用户未选,系统也会默认好推荐的支付方式进行结算。来看如下图所示的类图,我们用策略模式来模拟此业务场景。



首先创建 Payment 抽象类,定义支付规范和支付逻辑,代码如下。



import com.tom.pattern.strategy.pay.PayState;
/** * 支付渠道 * Created by Tom. */public abstract class Payment {
public abstract String getName();
//通用逻辑被放到抽象类里实现 public MsgResult pay(String uid, double amount){ //余额是否足够 if(queryBalance(uid) < amount){ return new MsgResult(500,"支付失败","余额不足"); } return new MsgResult(200,"支付成功","支付金额" + amount); }
protected abstract double queryBalance(String uid);}
复制代码


然后分别创建具体的支付方式,支付宝 AliPay 类的代码如下。



public class AliPay extends Payment { public String getName() { return "支付宝"; }
protected double queryBalance(String uid) { return 900; }}
复制代码


京东白条 JDPay 类的代码如下。




public class JDPay extends Payment { public String getName() { return "京东白条"; }
protected double queryBalance(String uid) { return 500; }}
复制代码


微信支付 WechatPay 类的代码如下。



public class WechatPay extends Payment { public String getName() { return "微信支付"; }
protected double queryBalance(String uid) { return 263; }}
复制代码


银联支付 UnionPay 类的代码如下。



public class UnionPay extends Payment { public String getName() { return "银联支付"; }
protected double queryBalance(String uid) { return 120; }}
复制代码


接着创建支付状态的包装类 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() { return "MsgResult{" + "code=" + code + ", data=" + data + ", msg='" + msg + '\'' + '}'; }}
复制代码


创建支付策略管理类。



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); } return strategy.get(payKey); }}
复制代码


创建订单 Order 类。



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(){ return pay(PayStrategy.DEFAULT_PAY); }
public MsgResult pay(String payKey){ Payment payment = PayStrategy.get(payKey); System.out.println("欢迎使用" + payment.getName()); System.out.println("本次交易金额为" + amount + ",开始扣款"); return payment.pay(uid,amount); }}
复制代码


最后编写客户端测试代码。



public static void main(String[] args) { Order order = new Order("1","2020031401000323",324.5); System.out.println(order.pay(PayStrategy.ALI_PAY));}
复制代码


运行结果如下图所示。



通过常见的业务场景举例,希望小伙伴们能够更深刻地理解策略模式。


【推荐】Tom弹架构:收藏本文,相当于收藏一本“设计模式”的书


本文为“Tom 弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!

如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tom 弹架构 』可获取更多技术干货!

发布于: 2021 年 11 月 05 日阅读数: 7
用户头像

Tom弹架构

关注

不只做一个技术者,更要做一个思考者 2021.10.22 加入

畅销书作者,代表作品: 《Spring 5核心原理与30个类手写实战》 《Netty 4核心原理与手写RPC框架实战》 《设计模式就该这样学》

评论

发布
暂无评论
使用策略模式重构电商折扣和支付场景