不得不说,在很多业务中,这种模式用得真的很香

这篇具有很好参考价值的文章主要介绍了不得不说,在很多业务中,这种模式用得真的很香。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

故事

“不能在写if else来拓展当前系统了,现在已经有三个支付场景了......”工位上,小猫看着电脑,挠着头。

就在刚刚,小猫接到了一个新需求,需要和客户公司打通资产,形成资产联动。说白了就是需要定制化对接客户公司的支付资产体系。除了这次接到的之外。前面其实已经对接了三家了。由于每家对接规范都不一样,历史对接的时候为了尽快上线,都是直接搞个else的新路由分支,然后去实现支付,退款。

在小猫看来,就是在堆屎山。牵一发而动全身的感觉真的很不好。由于本次的需求留有的时间还是相当充裕的,所以小猫下定决心,打算利用这次的拓展,将原来不合理的地方用上设计模式将其重构掉。

深思熟虑很久,小猫下定决心打算用“策略模式”重构一番。

聊聊策略模式

说到策略模式,老猫觉得这种设计模式在实际开发中使用其实是相当频繁的。老猫工作到现在也在很多业务场景中使用过这样的设计模式。例如,上述小猫遇到的第三方支付集成的问题上。另外的还有商城搞活动,针对不同的用户下单行为提供不同的折扣或者返现等活动。再例如商城运营人员根据不同的加价策略去定在售商品的价格等。

老猫工作十年中,对接过很多外部企业或者单位的接口,若业务定义一样,只是接口协议不同的业务其实往往都可以用到策略模式。
提炼一下适用场景如下:

(1)系统中有很多类,而它们的区别仅仅在于行为不同。

(2)一个系统需要动态地在几种算法中选择一种。

在很多业务中,这种模式用起来真的很香,既能够摆脱成堆的“if else”(当然关于 if else的优化,又是另外一个故事了,有兴趣的小伙伴可以看看这篇文章【接手了个项目,被if..else搞懵逼了】),另外写出来的代码本身拓展性也会比较好。

那么我们来看看策略模式,并且基于小猫遇到的场景问题,咱们来撸一下实现代码。

策略模式解决多路支付通道问题

在定义支付行为的时候,我们首先定义出常规的支付行为,咱们可以用接口interface的形式定义出来,当然也可以用abstract类的方式定义出来。这里老猫使用后者来定义。代码如下:

/**
 * @author 公众号:程序员老猫
 */
public abstract class Payment {
    //获取支付渠道的名称
    public abstract String getName();

    //查询用户余额
    protected abstract BigDecimal queryBalance(String uid);

    public PayState doPay(String uid, BigDecimal amount) {
        if (queryBalance(uid).compareTo(amount) < 0) {
            return new PayState(500, "支付失败", "账户余额不足");
        }
        return new PayState(200, "支付成功", "支付金额:" + amount);
    }
}

定义一个标准的支付状态类:

/**
 * @author 公众号:程序员老猫
 */
public class PayState {
    private int code;
    private String msg;
    private Object data;

    public PayState(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public String toString() {
        return ("pay state :[" + code + "]," + msg + ",order detail: " + data);
    }
}

接下来,咱们来模拟各个支付渠道,并且咱们能够知道在不同的支付渠道中,我们当前的账户余额是多少。咱们就拿用的比较多的微信、支付宝、京东支付等支付渠道来做模拟吧。

支付宝实现,并且账户中有900元:

public class AliPay extends Payment {
    @Override
    public String getName() {
        return "支付宝";
    }

    @Override
    protected BigDecimal queryBalance(String uid) {
        return new BigDecimal(900);
    }
}

微信支付,并且账户中有300元:

public class WxPay extends Payment{
    @Override
    public String getName() {
        return "微信";
    }

    @Override
    protected BigDecimal queryBalance(String uid) {
        return new BigDecimal(300);
    }
}

以此类推,京东支付。

public class JDPay extends Payment{
    @Override
    public String getName() {
        return "京东白条";
    }

    @Override
    protected BigDecimal queryBalance(String uid) {
        return new BigDecimal(400);
    }
}

定义好各种单一支付通道之后,其实我们就要组装策略了。把上述支付通道,加载到策略路由类中。老猫觉得这个地方也是策略模式中比较核心的点。

/**
 * @author 公众号:程序员老猫
 */
public class PayStrategy {
    public static final String ALI_PAY = "aliPay";
    public static final String WX_PAY = "wxPay";
    public static final String JD_PAY = "jdPay";
    public static final String DEFAULT = "wxPay";

    //初始化的时候装载支付行为策略
    private static Map<String,Payment> paymentMap = new HashMap<>();

    static {
        paymentMap.put(ALI_PAY,new AliPay());
        paymentMap.put(WX_PAY,new WxPay());
        paymentMap.put(JD_PAY,new JDPay());
        paymentMap.put(DEFAULT,new WxPay());
    }

    //调用的时候路由具体的支付策略
    public static Payment get(String payKey){
        if(!paymentMap.containsKey(payKey)){
            return paymentMap.get(DEFAULT);
        }
        return paymentMap.get(payKey);
    }
}

接下来,我们就模拟用户下订单支付行为了,具体如下:

/**
 * @author 程序员老猫
 * 下单场景
 */
public class Order {
    private String uid; //用户Id
    private String orderId; //订单Id
    private BigDecimal orderAmount; //支付金额

    public Order(String uid, String orderId, BigDecimal orderAmount) {
        this.uid = uid;
        this.orderId = orderId;
        this.orderAmount = orderAmount;
    }

    public PayState doPay() {
        return doPay(PayStrategy.DEFAULT);
    }

    public PayState doPay(String payKey) {
        Payment payment = PayStrategy.get(payKey);
        System.out.println("欢迎使用" + payment.getName());
        System.out.println("本次交易金额:" + orderAmount);
        return payment.doPay(uid, orderAmount);
    }
}

最终咱们来进行测试一下:

public class PayStrategyTest {
    public static void main(String[] args) {
        Order order = new Order("ktdaddy","20240425224901",new BigDecimal(245));

        System.out.println(order.doPay(PayStrategy.ALI_PAY));
    }
}

结果输出:

欢迎使用支付宝
本次交易金额:245
pay state :[200],支付成功,order detail: 支付金额:245

上述基本就是策略模式的使用了。老猫觉得应该还是比较清晰的。咱们简单看一下最终的调用类图:

不得不说,在很多业务中,这种模式用得真的很香

到这里很多小伙伴可能会问了,上面写的案例其实并没有结合我们实际的spring开发框架去实现策略模式,日常开发的过程中我们Java程序员主要用的还是spring框架。那么如果要结合咱们spring日常开发框架又是怎么去实现呢。那么接下来,咱们接着往下看。

SpringBoot下策略模式解决多路支付通道

其实核心的思想还是上面这几个要领,老猫在此不多做展开,只是给大家提供一些思路,然后提供一些简单的日常开发中使用的截图给大家参考。支付使用策略模式的核心的思想无非就下面两个。

(1)咱们需要不同的支付策略类。

(2)需要有路由支付策略类的路由类。

其实上面两个核心中,比较重要的还是第二点,咱们如果去初始化策略类。在上面案例中,老猫使用的静态方法块来装载各个策略方法。在spring中其实我们可以使用@PostConstruct注解,进行service策略的初始化装载。

如下首先定义一个标准的支付接口,并且实现一下:

public interface Payment {
    //获取支付渠道的名称
    String getCode();

    PayState doPay(String uid, BigDecimal amount);
}

然后实现这个接口,咱们举一个例子来说明

@Service
public class JDPay implements Payment {

    @Override
    public String getCode() {
        return "jdPay";
    }

    @Override
    public PayState doPay(String uid, BigDecimal amount) {
        return null;
    }
}

关键此时咱们看一下核心加载的地方。

/**
 * 程序员老猫
 **/
@Service
public class PayStrategy {
    @Autowired
    private Payment[] payments;

    //初始化的时候装载支付行为策略
    private static Map<String, Payment> paymentMap = new ConcurrentHashMap<>();


    @PostConstruct
    private void initRouteMap() {
        for (Payment externalPayService : payments) {
            paymentMap.put(externalPayService.getCode(), externalPayService);
        }
    }

    public Payment getPayment(String payCode) {
        return paymentMap.get(payCode);
    }
}

上述就是结合spring的核心策略模式的实现方式,老猫这里没有展开,但是最精华的部分,老猫觉得已经说清楚了。当然基于@PostConstruct进行策略加载的方式只是一种。大家可以实现spring自带的InitializingBean,在 Spring 容器完成 bean 的属性注入后,会调用 afterPropertiesSet() 方法来执行初始化逻辑。

总结

上述主要和大家分享了基于策略模式如何去做支付整合第三方支付的问题。当然这只是一个简单的案例,其实很多时候我们在实际的业务开发中很多地方都可以用到这样一个模式。在jdk源码中以及spring源码中也屡见不鲜。但是策略模式也不是万能的,存在优点的同时也存在缺点。

优点:

1、策略模式符合开闭原则。(当然有兴趣了解设计原则的小伙伴欢迎戳【违反这些设计原则,系统就等着“腐烂”】)

2、策略模式可以避免使用多重复的条件语句。例如优化if else。当然之前也老猫也写过类似博文。【接手了个项目,被if..else搞懵逼了】

3、使用策略模式可以提高算法的保密性和安全性。

缺点:

1、不像适配器模式,策略模式要求客户端需要知道所有的策略,并且自行决定使用哪类策略。关于适配器模式,感兴趣的小伙伴可以看这里【真香定律!我用这种模式重构了第三方登录】

2、策略类会越来越多,维护成本也会越来越高。文章来源地址https://www.toymoban.com/news/detail-858668.html

到了这里,关于不得不说,在很多业务中,这种模式用得真的很香的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 测试进阶必备,这5款http接口自动化测试工具真的很香

    现在市场上能做接口自动化测试的工具有很多,一搜一大把,让人眼花缭乱。我们去选择对应实现方式时,不管是框架体系还是成熟稳定的工具,核心目的都是期望引入的技术能在 最低投入 的情况下达到 最优效果 。 那么我们选择依据出来了: 一是最低投入。 二是最优效果

    2024年02月06日
    浏览(41)
  • Kotlin对象和单例模式:探索这种强大设计模式的好处

    在Kotlin中,使用\\\"object\\\"来定义一个单例对象。所谓单例对象,就是在整个应用程序中只有一个实例存在。简单来说,就好像只有一个蜘蛛侠一样,不可能同时有多个蜘蛛侠存在(除非是在处理平行宇宙的故事情节,但那是另外一回事)。在Kotlin中,单例对象也是如此。

    2024年02月10日
    浏览(46)
  • 你真的会性能测试吗?性能测试需求分析,从业务到数据(详细)...

    产品需求 业务场景: 一个问卷调查的功能,然后产品和业务会不定时通过前端界面去根据筛选条件查询相关问卷问题的答案明细,但是觉得很慢,让测试这边给出一个指标。 系统架构: MySQL数据库,所有问卷问题相关的数据都存储在同一张表,单台服务器,无缓存,通过一

    2024年02月10日
    浏览(59)
  • 小程序备案大整改!小作坊何去何从?开发者需依法履行备案手续,未按要求履行备案手续的,微信小程序不得开展业务,平台不提供上架服务

    为贯彻落实《中华人民共和国反电信网络诈骗法》、《互联网信息服务管理办法》及《非经营性互联网信息服务备案管理办法》等法律法规要求,配合相关部门做好移动互联网信息服务管理,根据2023年8月4日工信部发布的《工业和信息化部关于开展移动互联网应用程序备案工

    2024年02月11日
    浏览(49)
  • 【Kafka面试题1】Kafka消费者是pull(拉)还是push(推)模式,这种模式有什么好处?

    Kafka中的Producer和consumer采用的是push-and-pull模式 ,即Producer只管向broker push消息,consumer只管从broker pull消息,两者对消息的生产和消费是异步的。 1、控制权 使用pull(拉)模式主动权在消费者,消费者可以自由控制拉取数据的频率和数量,进而更好的控制消费的进度,更好的适应

    2024年02月12日
    浏览(34)
  • react当我们有两个完全不相关的组件想要通信时,就可以利用这种模式,其中一个组件负责订阅某个消息,而另一个元素则负责发送这个消息。使用Context配合

    在nextjs项目中,发现两个组件没啥关系,例如一个是一直存在的头部组件,另一个是页面中的组件,当我点击头部组件中的特定按钮时,把数据传递到页面组件中,页面组件接受到canshu数据后在做其他操作,那么他们两个如何通讯,通过context配合观察者模式实现。 首先在其

    2024年02月15日
    浏览(48)
  • Python设计模式:你的代码真的够优雅吗?

    当涉及到代码优化时,Python作为一种高级编程语言,具有广泛的应用领域和强大的功能。在软件开发中,设计模式是一种被广泛采用的解决问题的方案,它提供了一种在特定情境中重复使用的可行方案。在Python中,有许多设计模式可以用来优化代码。 其中两种常见的设计模式

    2024年01月25日
    浏览(42)
  • 期末考试还缺项目吗?黑马的图书借阅管理系统很香

    提示:黑马程序员的云借阅管理系统, 后端ssm框架, 前端jQuery, layui,模板引擎为thymeleaf。 有需要的小伙伴可以三连, 我会私聊你发源码。 提示:视频观看地址 bibi视频项目展示 提示:管理员全部功能, 用户部分功能 登录分为管理员登录, 普通用户登录, 不同身份登录拥有的权限

    2024年02月12日
    浏览(54)
  • 前后端都用得上的 Nginx 日常使用经验

    nginx 是一个高性能的开源反向代理服务器和 web 服务器,一般用来搭建静态资源服务器、负载均衡器、反向代理,本文将分享其在 Windows/docker 中的使用,使用 nssm 部署成服务的方案脚本,局域网中自定义域名解决https提示不安全的解决方案,以及一路踩过的坑。 高性能:事件驱

    2024年02月06日
    浏览(34)
  • 业务架构设计模式

    背景介绍 我们是CRO面向商家的业务技术团队,做商家营商环境治理业务已经4年了。作为垂直型业务技术团体(区别于平台技术团队),我们也面临大部分业务技术团队的拷问:业务技术与平台技术的差别是什么?业务技术如何做?如何理解业务?如何在短频快的业务节奏中

    2024年02月09日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包