SpringBoot 里用工厂模式优雅搞定“三码合一”支付
一、为什么要工厂模式?
做支付对接时,需求往往是这样的:
“明天加银联、后天加微信、大后天再来个数字人民币……”
如果业务层到处 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. 统一抽象
java
public interface PaymentService {
String pay(BigDecimal amount);
}就一个方法,干净利落,后续无论扩张到火星支付,接口不动。
2. 三个实现类(只贴一个,其余同理)
java
@Service("alipay") // Bean 名称就是渠道代号
public class AlipayServiceImpl implements PaymentService {
@Override
public String pay(BigDecimal amount) {
return "使用支付宝支付:" + amount + " 元";
}
}@Service 直接把实现类扔进 Spring 容器,key = "alipay"。
3. 工厂:核心就 10 行
java
@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 入口
java
@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 步搞定
- 新建
XxxServiceImpl实现PaymentService; - 打上
@Service("新渠道名"); - 打包部署,齐活。
Controller、Factory、老渠道代码一行不动!
六、可继续演进的 3 个小技巧
- 渠道级开关:在
paymentMap外包一层Optional+ 配置中心,动态上下线; - 策略升级:把
PaymentService扩展成PaymentStrategy,加入refund()、query()等默认方法,再用 Java 8 接口default实现; - 性能埋点:工厂里返回代理对象,统一打印耗时 / 异常,业务代码无感知。