通过【模板方法模式】,我实现了"财富"自由

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

需求

国庆长假结束了,领导也都休假完回来上班了,一到公司看到我闲着没事干,就给我安排了个任务。要我做一个支付模块提供给其他的业务系统使用,要求兼容多种支付渠道。话不多说,上号!

image.png

概述

模板方法模式,是一种行为设计模式。在一个抽象类中定义了执行的方法/模板,子类按需重写需要实现的不同逻辑,调用时以抽象类中定义的方式运行。

适用场景

  • 多个子类拥有相同的方法,且逻辑部分相似度高。
  • 核心的或者复杂的方法需要被反复调用,可以考虑做为模板方法。

角色

抽象模板:定义一个或多个抽象方法,让子类实现具体逻辑。同时在当前类中定义好算法框架,实现对抽象方法的调度,完成固定的逻辑。

具体实现:给出抽象方法的不同实现,使得抽象模板中逻辑可得到不同的实现。

代码实现

抽象模板:因为抽象类不能注入到容器中,所以这里多了一层PaymentService来实现模板部分,具体的抽象方法定义在了BasePayment抽象类中。同时还定义了一个枚举类,用来获取对应的bean

public class PaymentService {

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 支付请求
     * @param type 支付类型
     * @return java.lang.String
     */
    public final String pay(String type, String params){
        System.out.println("解密验签");
        // 其它固定的逻辑

        // 通过容器得到实例
        BasePayment basePayment = getPaymentBean(PayModel.valueOf(type).getServiceName());
        String result = basePayment.doPay(params);

        System.out.println("加签加密");
        // 返回结果
        return result;
    }
    /**
     * 查询请求
     * @param type 支付类型
     * @return java.lang.String
     */
    public final String query(String type, String params){
        System.out.println("解密验签");
        // 其它固定的逻辑

        // 通过容器得到实例
        BasePayment basePayment = getPaymentBean(PayModel.valueOf(type).getServiceName());
        String result = basePayment.doQuery(params);

        System.out.println("加签加密");
        // 返回结果
        return result;
    }
    /**
     * 退款请求
     * @param type 支付类型
     * @return java.lang.String
     */
    public final String refund(String type, String params){
        System.out.println("解密验签");
        // 其它固定的逻辑

        // 通过容器得到实例
        BasePayment basePayment = getPaymentBean(PayModel.valueOf(type).getServiceName());
        String result = basePayment.doRefund(params);

        System.out.println("加签加密");
        // 返回结果
        return result;
    }
    
    /**
     * 获取Bean
     *
     * @param serviceName 服务名
     * @return BasePayment
     */
    public BasePayment getPaymentBean(String serviceName){
        return (BasePayment)applicationContext.getBean(serviceName);
    }
}
复制代码
public abstract class BasePayment {
    /**
     * 支付请求
     *
     * @param params 支付参数
     * @return java.lang.String
     */
    protected abstract String doPay(String params);

    /**
     * 查询请求
     *
     * @param params 查询参数
     * @return java.lang.String
     */
    protected abstract String doQuery(String params);

    /**
     * 退款请求
     *
     * @param params 退款参数
     * @return java.lang.String
     */
    protected abstract String doRefund(String params);
}
复制代码
public enum PayModel {
    /**
     * 微信
     */
    WX_PAY("weiXinPayment"),
    /**
     * 支付宝
     */
    AL_PAY("aliPayment"),
    /**
     * 收款码
     */
    SCAN_PAY("scanPayment"),
    /**
     * 付款码
     */
    SWEPT_PAY("sweptPayment"),
    /**
     * 银联
     */
    YL_PAY("ylPayment");

    private String serviceName;

    PayModel(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getServiceName() {
        return serviceName;
    }
}
复制代码

具体实现: 实现了微信支付,商家收款码支付,用户付款码支付等多种支付方式,每种支付方式所需的参数不同,处理逻辑也不同。

@Service("weiXinPayment")
public class WeiXinPayment extends BasePayment{
    /**
     * 微信预付单
     *
     * @param params 支付参数
     * @return java.lang.String
     */
    @Override
    protected String doPay(String params) {
        // 设置必要参数,发起预付单请求获取 prepaid
        return "微信预付单:" + params;
    }


    /**
     * 微信支付状态查询
     *
     * @param params 查询参数
     * @return java.lang.String
     */
    @Override
    protected String doQuery(String params) {
        return "微信支付状态查询:" + params;
    }


    /**
     * 微信支付退款
     *
     * @param params 退款参数
     * @return java.lang.String
     */
    @Override
    protected String doRefund(String params) {
        return "微信支付退款:" + params;
    }
}
复制代码
@Service("scanPayment")
public class ScanPayment extends BasePayment {
    /**
     * 收款码申请
     *
     * @param params 支付参数
     * @return java.lang.String
     */
    @Override
    protected String doPay(String params) {
        // 申请动态收款二维码
        return "收款码申请:" + params;
    }

    /**
     * 收款码支付结果查询
     *
     * @param params 查询参数
     * @return java.lang.String
     */
    @Override
    protected String doQuery(String params) {
        return "收款码支付结果查询:" + params;
    }

    /**
     * 收款码支付退款
     *
     * @param params 退款参数
     * @return java.lang.String
     */
    @Override
    protected String doRefund(String params) {
        return "收款码支付退款:" + params;
    }
}
复制代码
@Service("sweptPayment")
public class SweptPayment extends BasePayment{
    /**
     * 付款码支付
     *
     * @param params 支付参数
     * @return java.lang.String
     */
    @Override
    protected String doPay(String params) {
        // 根据用户付款码进行扣款
        return "付款码支付:" + params;
    }

    /**
     * 付款码支付结果查询
     *
     * @param params 查询参数
     * @return java.lang.String
     */
    @Override
    protected String doQuery(String params) {
        return "付款码支付结果查询:" + params;
    }

    /**
     * 付款码支付退款
     *
     * @param params 退款参数
     * @return java.lang.String
     */
    @Override
    protected String doRefund(String params) {
        return "付款码支付退款:" + params;
    }
}
复制代码

案例结果:这里为了演示将具体实现中返回结果修改成为控制台打印

public class TemplateMethodPattern {
    public static void main(String[] args) {
        PaymentService paymentService = new PaymentService();
        paymentService.pay("WX_PAY", "openid");
        System.out.println("=================================");
        paymentService.pay("SCAN_PAY", "price");
        System.out.println("=================================");
        paymentService.pay("SWEPT_PAY", "PaymentCode");
    }
}
复制代码

image.png

小结

优点

  1. 封装不变部分,扩展可变部分
  2. 提取公共代码,便于维护
  3. 行为由父类控制,子类实现

缺点

  1. 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大

最后

文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!!!

如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!

猜你喜欢

转载自juejin.im/post/7018573684763803678