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

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

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 使用策略模式重构支付方式选择场景

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

7f33a27b177e3869f5caa4b6b3aa8c17.png

首先创建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));
}

运行结果如下图所示。

9a3bc90f1fb81641884c3c05b53df4c3.png

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


【推荐】Tom弹架构:30个设计模式真实案例(附源码),挑战年薪60W不是梦


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

如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。

相关文章
拍卖软件开发定制直播竞价商城成品源码优势
在数字化时代,拍卖业务已经由传统的实体拍卖过渡到了在线平台。为了满足日益增长的市场需求,拍卖业务领域面临着两种主要选择:自定义拍卖软件开发和使用“东莞梦幻网络科技”已有拍卖平台的现成源码解决方案。在本文中,我们将深入探讨这两种方法的各自优势,以帮助您更好地了解哪种适合满足您的业务需求。
|
2月前
|
存储 运维 分布式计算
用马斯克五步工作法重构支付宝商家账单
支付宝中国数据团队在过去的一年里应用马斯克的五步工作法重构了有 10 年历史之久的支付宝商家账单,整体复杂度减少 60%,时效性提升 1 小时,计存成本降低 30%,理解和运维成本大幅下降。复杂度是很多问题的根源,既会增加运维的成本,又降低了支撑业务的效率。账单重构的经验表明,相当大比例的复杂度是没有必要的,我们应该致力于把复杂的事情变简单,而不是倒过来做“防御性编程”。希望本文对想要降低系统复杂度的同学或者项目有所帮助。
用马斯克五步工作法重构支付宝商家账单
|
3月前
|
存储 运维 搜索推荐
重构支付宝商家账单问题之重构支付宝商家账单的目标是什么,如何实现
重构支付宝商家账单问题之重构支付宝商家账单的目标是什么,如何实现
|
3月前
|
编解码
重构支付宝商家账单问题之在重构过程中,替换老账单如何操作
重构支付宝商家账单问题之在重构过程中,替换老账单如何操作
|
设计模式 SQL 数据库
淘东电商项目(61) -聚合支付(基于模板方法设计模式管理支付回调)
淘东电商项目(61) -聚合支付(基于模板方法设计模式管理支付回调)
81 0
|
设计模式 算法 Java
淘东电商项目(58) -聚合支付(基于设计模式自动跳转支付接口)
淘东电商项目(58) -聚合支付(基于设计模式自动跳转支付接口)
76 0
|
设计模式 SQL 数据库
淘东电商项目(62) -聚合支付(基于模板方法设计模式管理支付回调-支付宝)
淘东电商项目(62) -聚合支付(基于模板方法设计模式管理支付回调-支付宝)
63 0
|
SQL NoSQL Java
把优惠券系统设计的炉火纯青!(2)
公司新来一个同事,把优惠券系统设计的炉火纯青!
156 0
把优惠券系统设计的炉火纯青!(2)
|
Java 测试技术 Spring
把优惠券系统设计的炉火纯青!(1)
把优惠券系统设计的炉火纯青!
143 0
把优惠券系统设计的炉火纯青!(1)
|
SQL 关系型数据库 MySQL
链动2+1系统开发玩法规则 | 链动2+1系统开发成品源码实例
“链动2+1”是一种促进企业和品牌迅速建立起获客团队、拓宽客源渠道、促进销售增长的一种新模式。 这是一种在传统的分销模式基础上的,并且合理合规,主要是为了激发员工的积极性,鼓励顾客带新客户,而顾客除了可以获得折扣外,还可以获得一定的提成和奖金。