SPRING 3 分钟 1,955 字

SpringBoot 里用工厂模式优雅搞定“三码合一”支付

0阅读

一、为什么要工厂模式?

做支付对接时,需求往往是这样的:
“明天加银联、后天加微信、大后天再来个数字人民币……”
如果业务层到处 new AlipayService()、new WechatService(),改一次全改,加一次全加,耦合得亲妈都不认识。
工厂模式把“对象的创建”与“对象的使用”彻底解耦:

  • 新增支付渠道,业务代码 0 改动;
  • 切换渠道,只改一行字符串;
  • 统一异常、日志、监控,一个地方收口。

二、整体架构图(文字版)

PayController(@RestController)
        ↓ 调用
PaymentFactory(@Component)
        ↓ 根据 type 从 Map 里拿
PaymentService(统一接口)
        ↓ 三个实现类
AlipayServiceImpl(@Service("alipay"))
UnionpayServiceImpl(@Service("unionpay"))
WechatServiceImpl(@Service("wechat"))

Spring 启动时会把所有 PaymentService 实现类扫进容器,并按 Bean 名称塞进 Map,工厂里直接 get(type) 就能拿到对应实例。
全程无 if/else、无 switch,开闭原则拉满。


三、代码 walkthrough

1. 统一抽象

public interface PaymentService {
    String pay(BigDecimal amount);
}

就一个方法,干净利落,后续无论扩张到火星支付,接口不动。

2. 三个实现类(只贴一个,其余同理)

@Service("alipay")   // Bean 名称就是渠道代号
public class AlipayServiceImpl implements PaymentService {
    @Override
    public String pay(BigDecimal amount) {
        return "使用支付宝支付:" + amount + " 元";
    }
}

@Service 直接把实现类扔进 Spring 容器,key = "alipay"。

3. 工厂:核心就 10 行

@Component
public class PaymentFactory {
    // Spring 会自动把 {alipay=AlipayServiceImpl, unionpay=..., wechat=...} 注入进来
    @Autowired
    private Map<String, PaymentService> paymentMap = new ConcurrentHashMap<>();

    public PaymentService getService(String type) {
        PaymentService service = paymentMap.get(type.toLowerCase());
        if (service == null) {
            throw new IllegalArgumentException("暂不支持的支付类型:" + type);
        }
        return service;
    }
}

关键点:

  • Map 的 key 就是 Bean 名称,value 是实例;
  • 大小写不敏感,统一 toLowerCase();
  • 找不到直接抛异常,避免空指针到处飞。

4. 对外 REST 入口

@RestController
@RequestMapping("/pay")
public class PayController {
    @Autowired
    private PaymentFactory factory;

    @GetMapping
    public String pay(@RequestParam String type,
                      @RequestParam BigDecimal amount) {
        return factory.getService(type).pay(amount);
    }
}

一行代码完成“路由 + 业务”,新增渠道这里永远不改。


四、自测一把

请求 结果
GET /pay?type=alipay&amount=100 使用支付宝支付:100 元
GET /pay?type=wechat&amount=99.9 使用微信支付:99.9 元
GET /pay?type=doge&amount=1 暂不支持的支付类型:doge

五、想加新渠道?3 步搞定

  1. 新建 XxxServiceImpl 实现 PaymentService;
  2. 打上 @Service("新渠道名");
  3. 打包部署,齐活。
    Controller、Factory、老渠道代码一行不动!

六、可继续演进的 3 个小技巧

  1. 渠道级开关:在 paymentMap 外包一层 Optional + 配置中心,动态上下线;
  2. 策略升级:把 PaymentService 扩展成 PaymentStrategy,加入 refund()、query() 等默认方法,再用 Java 8 接口 default 实现;
  3. 性能埋点:工厂里返回代理对象,统一打印耗时 / 异常,业务代码无感知。