news 2026/6/17 21:37:49

支付系统基于渠道编码路由支付实现(策略模式实战完整版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
支付系统基于渠道编码路由支付实现(策略模式实战完整版)

目录

一、业务背景

二、整体架构分层

三、完整实战代码(SpringBoot + Java)

1. 渠道编码常量(统一标识渠道)

2. 统一入参 / 出参 DTO(屏蔽渠道差异)

3. 策略顶层接口 IPayChannel(策略模式核心抽象)

4. 各渠道具体策略实现(ConcreteStrategy)

4.1 微信支付实现

4.2 支付宝支付实现

4.3 银联支付实现

5. 渠道工厂 PayChannelFactory(路由核心:渠道编码匹配实现类)

6. 支付上下文服务 PayService(对外统一业务层)

7. Controller 测试入口

四、测试效果

请求 1:微信支付

请求 2:支付宝支付

五、策略模式核心优势(支付系统落地价值)

1. 完美符合开闭原则

2. 消除巨型 if-else 分支

3. 职责单一,代码隔离

4. 易于扩展通用能力

5. 支持动态切换渠道

六、生产环境进阶优化方案

1. 渠道配置抽离(数据库动态配置)

2. 增加渠道开关控制

3. 渠道缓存 + 懒加载

4. 统一异常捕获

5. 结合模板方法模式优化重复逻辑

七、模式角色对应总结

八、对比 if-else 方案的致命缺陷


一、业务背景

支付系统对接多家支付渠道:微信支付、支付宝、银联、云闪付、抖音支付等。 每家渠道的下单、退款、查询订单、回调验签逻辑完全不同:

  • 支付宝:RSA2 签名、公钥验签、统一收单接口
  • 微信支付:V3 证书、AES 加解密、商户号 + 子商户
  • 银联:国密 SM2、报文 XML 格式 如果用大量if/else if(channelCode == "WECHAT")硬编码:
  1. 新增渠道要改核心支付服务,违反开闭原则
  2. 代码臃肿、分支几十条,维护困难
  3. 单元测试、渠道单独灰度发布无法隔离

解决方案:策略模式

  • 策略接口:统一支付操作标准
  • 具体策略:每个渠道单独实现一套逻辑
  • 策略工厂:根据渠道编码channelCode匹配对应实现类
  • 上下文服务:对外统一入口,屏蔽渠道差异

二、整体架构分层

支付入口 Controller ↓ PayService(上下文,调用工厂获取策略) ↓ PayChannelFactory 渠道工厂(核心路由:channelCode → 实现类) ↓ IPayChannel 策略顶层接口(定义统一支付能力) ├─ WechatPayChannel 微信策略实现 ├─ AlipayChannel 支付宝策略实现 ├─ UnionPayChannel 银联策略实现 └─ 新增支付渠道只新增实现类,不改动原有业务代码

三、完整实战代码(SpringBoot + Java)

1. 渠道编码常量(统一标识渠道)

/** * 支付渠道编码,工厂路由唯一key */ public class PayChannelCode { // 微信支付 public static final String WECHAT_PAY = "WECHAT_PAY"; // 支付宝 public static final String ALIPAY = "ALIPAY"; // 银联支付 public static final String UNION_PAY = "UNION_PAY"; }

2. 统一入参 / 出参 DTO(屏蔽渠道差异)

/** * 统一支付下单请求 */ @Data public class PayOrderDTO { // 渠道编码,工厂路由核心字段 private String channelCode; // 商户订单号 private String outTradeNo; // 支付金额 分 private Long amount; // 商品描述 private String subject; // 支付回调地址 private String notifyUrl; } /** * 统一支付返回结果 */ @Data public class PayResultVO { // 支付跳转链接/二维码/小程序支付参数 private String payInfo; // 渠道交易号 private String channelTradeNo; // 是否成功 private Boolean success; }

3. 策略顶层接口 IPayChannel(策略模式核心抽象)

所有支付渠道必须实现该接口,定义统一支付行为

/** * 支付渠道策略接口 * 所有第三方支付渠道实现该接口,统一行为标准 */ public interface IPayChannel { /** * 标识当前渠道编码,工厂根据该值匹配实现类 * @return 渠道编码:WECHAT_PAY / ALIPAY ... */ String getChannelCode(); /** * 统一创建支付单 */ PayResultVO createPayOrder(PayOrderDTO dto); /** * 统一订单退款 */ default void refund() { // 可选默认实现,部分渠道逻辑通用 } /** * 支付回调验签 */ String verifyNotify(String notifyData); }

4. 各渠道具体策略实现(ConcreteStrategy)

4.1 微信支付实现
@Component public class WechatPayChannel implements IPayChannel { // 标记当前渠道编码,工厂路由依据 @Override public String getChannelCode() { return PayChannelCode.WECHAT_PAY; } @Override public PayResultVO createPayOrder(PayOrderDTO dto) { System.out.println("=== 执行微信支付下单逻辑 ==="); // 1. 读取微信商户配置(证书、商户号、APIv3密钥) // 2. 组装微信V3请求报文 // 3. 发送http请求调用微信统一下单接口 // 4. 封装小程序/JSAPI支付参数返回 PayResultVO vo = new PayResultVO(); vo.setSuccess(true); vo.setPayInfo("微信支付JSAPI参数json"); vo.setChannelTradeNo("420000288888123456"); return vo; } @Override public String verifyNotify(String notifyData) { // 微信V3 AES解密、证书验签逻辑 return "微信回调验签通过"; } }
4.2 支付宝支付实现
@Component public class AlipayChannel implements IPayChannel { @Override public String getChannelCode() { return PayChannelCode.ALIPAY; } @Override public PayResultVO createPayOrder(PayOrderDTO dto) { System.out.println("=== 执行支付宝支付下单逻辑 ==="); // 1. 读取支付宝appId、私钥、支付宝公钥 // 2. RSA2签名组装请求参数 // 3. 调用alipay.trade.page.pay PayResultVO vo = new PayResultVO(); vo.setSuccess(true); vo.setPayInfo("支付宝支付跳转url"); vo.setChannelTradeNo("2026061722001404981412345678"); return vo; } @Override public String verifyNotify(String notifyData) { // 支付宝公钥验签逻辑 return "支付宝回调验签通过"; } }
4.3 银联支付实现
@Component public class UnionPayChannel implements IPayChannel { @Override public String getChannelCode() { return PayChannelCode.UNION_PAY; } @Override public PayResultVO createPayOrder(PayOrderDTO dto) { System.out.println("=== 执行银联支付下单逻辑 ==="); // 国密SM2签名、组装XML报文、调用银联网关 PayResultVO vo = new PayResultVO(); vo.setSuccess(true); vo.setPayInfo("银联收银台地址"); vo.setChannelTradeNo("8888001122334455"); return vo; } @Override public String verifyNotify(String notifyData) { return "银联回调验签通过"; } }

5. 渠道工厂 PayChannelFactory(路由核心:渠道编码匹配实现类)

核心作用:启动时加载所有IPayChannel实现,存入 Map,key=channelCode,运行时根据编码快速获取对应策略

import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.HashMap; import java.util.List; import java.util.Map; @Component public class PayChannelFactory { // Spring自动注入所有实现IPayChannel的Bean @Resource private List<IPayChannel> payChannelList; // 路由缓存Map:key=渠道编码,value=渠道策略实现类 private final Map<String, IPayChannel> channelMap = new HashMap<>(); /** * 项目启动完成后初始化渠道映射关系 */ @PostConstruct public void initChannelMap() { for (IPayChannel channel : payChannelList) { String code = channel.getChannelCode(); // 防重复渠道编码 if (channelMap.containsKey(code)) { throw new RuntimeException("渠道编码重复:" + code); } channelMap.put(code, channel); } System.out.println("支付渠道工厂初始化完成,已加载渠道:" + channelMap.keySet()); } /** * 根据渠道编码获取对应支付策略实现(核心路由方法) * @param channelCode 渠道编码 * @return 渠道实现类 */ public IPayChannel getPayChannel(String channelCode) { IPayChannel payChannel = channelMap.get(channelCode); if (payChannel == null) { throw new RuntimeException("不存在该支付渠道:" + channelCode); } return payChannel; } }

6. 支付上下文服务 PayService(对外统一业务层)

上层业务只依赖 Service,不需要关心底层渠道实现,完全解耦

import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class PayService { @Resource private PayChannelFactory channelFactory; /** * 统一创建支付订单入口 * 只传入渠道编码,内部自动路由对应渠道实现 */ public PayResultVO createPayOrder(PayOrderDTO dto) { // 1. 根据渠道编码路由到对应支付策略 IPayChannel payChannel = channelFactory.getPayChannel(dto.getChannelCode()); // 2. 调用对应渠道的下单方法 return payChannel.createPayOrder(dto); } /** * 支付回调统一处理 */ public String handleNotify(String channelCode, String notifyData) { IPayChannel payChannel = channelFactory.getPayChannel(channelCode); return payChannel.verifyNotify(notifyData); } }

7. Controller 测试入口

import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/pay") public class PayController { @Resource private PayService payService; @PostMapping("/create") public PayResultVO createPay(@RequestBody PayOrderDTO dto) { return payService.createPayOrder(dto); } }

四、测试效果

请求 1:微信支付

POST /pay/create { "channelCode": "WECHAT_PAY", "outTradeNo": "ORDER20260617001", "amount": 9900, "subject": "商品支付", "notifyUrl": "https://xxx.com/pay/notify" }

控制台输出:=== 执行微信支付下单逻辑 ===

请求 2:支付宝支付

{ "channelCode": "ALIPAY", "outTradeNo": "ORDER20260617002", "amount": 19900, "subject": "会员充值", "notifyUrl": "https://xxx.com/pay/notify" }

控制台输出:=== 执行支付宝支付下单逻辑 ===

五、策略模式核心优势(支付系统落地价值)

1. 完美符合开闭原则

新增渠道(如抖音支付、京东支付)只需要:

  1. 新增常量DOUYIN_PAY
  2. 新建DouyinPayChannel实现IPayChannel
  3. 实现所有接口方法不需要修改工厂、PayService、Controller 任何一行代码

2. 消除巨型 if-else 分支

传统写法随着渠道增多,分支会膨胀到几十行,可读性极差; 策略模式通过 Map 编码映射,时间复杂度 O (1) 路由渠道,性能更高。

3. 职责单一,代码隔离

每个渠道的签名、报文、异常、配置全部隔离在自己实现类, 微信出问题不会影响支付宝逻辑,便于单独排查、单元测试、灰度切换。

4. 易于扩展通用能力

接口可以新增统一方法(如查询订单、关闭订单、转账),所有渠道统一约束。

5. 支持动态切换渠道

运行时只需要修改传入的channelCode,即可无缝切换支付渠道,适合多渠道容灾、渠道比价切换。

六、生产环境进阶优化方案

1. 渠道配置抽离(数据库动态配置)

实际项目不会硬编码商户参数,新增渠道表pay_channel_config: channelCode、商户号、密钥、开关、手续费、优先级,在实现类中通过渠道编码查询对应配置。

2. 增加渠道开关控制

工厂获取渠道时增加校验:渠道是否启用,未启用直接抛出异常。

public IPayChannel getPayChannel(String channelCode) { // 1. 查询渠道配置是否启用 PayChannelConfig config = configService.getByCode(channelCode); if (!config.getEnable()) { throw new RuntimeException("渠道已关闭"); } // 2. 返回策略实现 return channelMap.get(channelCode); }

3. 渠道缓存 + 懒加载

渠道非常多时,可改为懒加载策略 Bean,减少启动内存占用。

4. 统一异常捕获

IPayChannel实现内部捕获各渠道 SDK 异常,统一封装自定义支付异常,上层不需要区分渠道异常类型。

5. 结合模板方法模式优化重复逻辑

部分渠道存在通用逻辑(参数校验、日志打印),可以增加抽象父类AbstractPayChannel

public abstract class AbstractPayChannel implements IPayChannel { @Override public PayResultVO createPayOrder(PayOrderDTO dto) { // 通用前置:参数校验、打印请求日志 checkParam(dto); // 交给子类实现渠道特有逻辑 return doCreateOrder(dto); } // 子类实现特有下单逻辑 protected abstract PayResultVO doCreateOrder(PayOrderDTO dto); }

融合策略模式 + 模板方法,通用逻辑抽离,大幅减少重复代码。

七、模式角色对应总结

策略模式角色支付系统对应代码作用
Strategy(策略抽象)IPayChannel定义所有支付渠道统一行为规范
ConcreteStrategy(具体策略)WechatPayChannel/AlipayChannel单渠道专属业务实现
Context(上下文)PayService对外业务入口,屏蔽底层路由细节
Factory(策略工厂)PayChannelFactory根据 channelCode 路由匹配对应策略实例

八、对比 if-else 方案的致命缺陷

如果不用策略,传统写法:

// PayService 臃肿写法,极度难维护 public PayResultVO create(PayOrderDTO dto){ if("WECHAT_PAY".equals(dto.getChannelCode())){ // 微信几百行代码 }else if("ALIPAY".equals(dto.getChannelCode())){ // 支付宝几百行代码 }else if("UNION_PAY".equals(dto.getChannelCode())){ // 银联代码 } // 新增渠道继续加else if }
  • 新增渠道必须修改核心业务类,上线需要全量发布
  • 代码耦合严重,改微信逻辑容易误改支付宝分支
  • 单元测试需要覆盖所有分支,测试成本极高
  • 代码行数爆炸,可读性极差
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/17 21:27:56

嵌入式RTOS调试与任务调度实战:从printf到多任务通信

1. 嵌入式调试与RTOS&#xff1a;从printf到任务调度的实战指南在嵌入式开发这个行当里摸爬滚打十几年&#xff0c;我越来越觉得&#xff0c;能把代码烧进芯片跑起来只是第一步&#xff0c;真正考验功力的&#xff0c;是当它跑飞了、卡死了、或者输出一堆乱码的时候&#xff0c…

作者头像 李华
网站建设 2026/6/17 21:24:50

嵌入式调试器组件化架构:DLL模块化设计与四大核心组件实战

1. 嵌入式调试器组件化架构&#xff1a;从原理到实战在嵌入式开发的深水区&#xff0c;调试往往是最耗费心力的环节。想象一下&#xff0c;你的代码在目标板上跑飞了&#xff0c;内存数据莫名其妙地被改写&#xff0c;或者ADC采样值总是不对&#xff0c;而你手头只有闪烁的LED和…

作者头像 李华
网站建设 2026/6/17 21:21:15

CLI-Anything终极指南:如何让任何软件原生支持AI代理操作

CLI-Anything终极指南&#xff1a;如何让任何软件原生支持AI代理操作 【免费下载链接】CLI-Anything "CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/ 项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything …

作者头像 李华
网站建设 2026/6/17 21:17:36

终极指南:3个步骤让Windows完美查看和转换iPhone的HEIF图片

终极指南&#xff1a;3个步骤让Windows完美查看和转换iPhone的HEIF图片 【免费下载链接】HEIF-Utility HEIF Utility - View/Convert Apple HEIF images on Windows. 项目地址: https://gitcode.com/gh_mirrors/he/HEIF-Utility 你是否也遇到过这样的烦恼&#xff1f;用…

作者头像 李华
网站建设 2026/6/17 21:16:58

超自动化运维的度量指标:如何证明其价值?

在数字化转型的浪潮中&#xff0c;越来越多的企业开始拥抱超自动化运维——部署智能巡检机器人、搭建自动化告警处置平台、构建安全编排与响应&#xff08;SOAR&#xff09;体系。然而&#xff0c;当项目进入汇报阶段&#xff0c;一个关键问题总是浮现&#xff1a;如何向管理层…

作者头像 李华