用Java工厂模式重构多支付方式系统:从混乱到优雅的架构蜕变
📚 目录导读
- 问题背景:为什么需要重构支付系统?
- 传统支付实现的痛点:if-else地狱与扩展困境
- 工厂模式核心思想:解耦创建与使用
- 实战重构全过程:从接口定义到工厂实现(含代码)
- 高级扩展:结合枚举与反射的自动注册工厂
- 常见问答:开发中最纠结的5个问题
- 工厂模式在支付场景的最佳实践
问题背景
大多数电商或SaaS系统在初期,支付方式往往只有微信和支付宝,但随着业务发展,你可能需要接入银联、PayPal、Stripe、甚至加密货币支付,如果此时代码还停留在 if (type.equals("wechat")) 的层次,那维护成本会像滚雪球一样增长。工厂模式(Factory Pattern) 正是解决这类“创建对象逻辑复杂且频繁变化”问题的利器。

传统支付实现的痛点
我们先看一个典型的“坏代码”示例:
public class PaymentService {
public void pay(String type, double amount) {
if ("WECHAT".equals(type)) {
WechatPay wechat = new WechatPay();
wechat.pay(amount);
} else if ("ALIPAY".equals(type)) {
Alipay alipay = new Alipay();
alipay.pay(amount);
} else if ("UNION".equals(type)) {
// 每新增一种支付,就要加一个else if
UnionPay union = new UnionPay();
union.pay(amount);
} else {
throw new UnsupportedOperationException("不支持的支付方式");
}
}
}
问题清单:
- ❌ 违反开闭原则:新增支付需要修改核心业务代码
- ❌ 代码臃肿:支付逻辑与创建逻辑耦合
- ❌ 测试困难:每个分支都需要模拟
- ❌ 无法复用:支付对象的创建散落在各处
工厂模式核心思想
工厂模式本质是将“对象创建”的职责从业务代码中剥离,在支付系统中,我们创建一个“支付工厂”,它根据传入的支付类型,返回对应的支付处理对象。核心三要素:
- 产品接口:所有支付方式共同遵守的契约(如
Payment接口) - 具体产品:如
WechatPay,Alipay等实现类 - 工厂类:封装创建逻辑,返回正确的产品实例
实战重构全过程
1 定义支付接口
public interface Payment {
boolean pay(BigDecimal amount);
void refund(String orderId, BigDecimal amount);
String getChannelName();
}
2 实现具体支付类
public class WechatPay implements Payment {
@Override
public boolean pay(BigDecimal amount) {
// 调用微信支付SDK
System.out.println("微信支付:" + amount + "元");
return true;
}
@Override public void refund(String orderId, BigDecimal amount) { /*...*/ }
@Override public String getChannelName() { return "微信支付"; }
}
public class Alipay implements Payment {
// 类似实现...
}
3 建立支付工厂
public class PaymentFactory {
public static Payment createPayment(String channel) {
switch (channel.toUpperCase()) {
case "WECHAT": return new WechatPay();
case "ALIPAY": return new Alipay();
case "UNION": return new UnionPay();
default: throw new IllegalArgumentException("未知支付渠道: " + channel);
}
}
}
4 业务调用变得极致简洁
public class OrderService {
public void processOrder(String channel, BigDecimal amount) {
Payment payment = PaymentFactory.createPayment(channel);
payment.pay(amount);
// 如果需要退款:payment.refund(orderId, amount);
}
}
重构后的变化:
- 新增支付方式只需:①新建实现类 ②在工厂的switch加一行
- 原有业务代码零改动
- 每个支付类可独立测试
高级扩展:自动注册工厂
如果支付方式暴增至20+种,手动维护switch依然痛苦,更优雅的方式是利用反射+注解实现自动注册:
// 注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PaymentType {
String value();
}
// 使用方式
@PaymentType("WECHAT")
public class WechatPay implements Payment { ... }
// 自动扫描工厂
public class AutoPaymentFactory {
private static final Map<String, Payment> PAYMENT_MAP = new HashMap<>();
static {
// 扫描指定包下所有@PaymentType注解的类
Reflections reflections = new Reflections("com.example.payment.impl");
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(PaymentType.class);
for (Class<?> clazz : annotated) {
PaymentType annotation = clazz.getAnnotation(PaymentType.class);
try {
PAYMENT_MAP.put(annotation.value(),
(Payment) clazz.getDeclaredConstructor().newInstance());
} catch (Exception e) { /* 处理异常 */ }
}
}
public static Payment createPayment(String channel) {
Payment payment = PAYMENT_MAP.get(channel);
if (payment == null) throw new IllegalArgumentException();
return payment;
}
}
优势:新增支付方式时,只需添加带注解的类,工厂完全不需要修改。
常见问答
Q1: 工厂模式和策略模式有什么区别?
A: 工厂模式关注对象的创建(如何拿到支付对象);策略模式关注算法的封装(如何执行支付),实际项目中往往同时使用:工厂创建策略对象。
Q2: 是否一定要用静态工厂?需要Spring怎么办?
A: 可以注入Spring容器,让工厂成为Bean并管理依赖,推荐方式:
@Component
public class SpringPaymentFactory {
@Autowired private Map<String, Payment> paymentMap; // Spring会自动注入所有Payment实现
public Payment getPayment(String type) {
return paymentMap.get(type);
}
}
Q3: 如果支付对象创建时需要额外参数(如API密钥)?
A: 使用抽象工厂模式,例如创建 WechatPay 时需要 appId 和 mchId,可抽象出工厂接口 PaymentFactory { Payment create(Config config); }。
Q4: 工厂模式会不会导致类数量爆炸?
A: 每个支付方式一个类,这是符合单一职责的,相比在原有类中堆砌if-else,灵活性和可读性大幅提升,可以用内部类+枚举简化少量支付场景。
Q5: 如何保证线程安全?
A: 如果是无状态的支付处理器(不保存用户状态),可以复用单例,工厂中缓存已创建的支付实例:
public class SingletonPaymentFactory {
private static final Map<String, Payment> CACHE = new ConcurrentHashMap<>();
public static Payment create(String channel) {
return CACHE.computeIfAbsent(channel, ch -> {
// 创建逻辑...
});
}
}
用Java工厂模式重构支付系统的核心收益:
| 维度 | 重构前 | 重构后 |
|---|---|---|
| 扩展性 | 新增支付需修改核心代码 | 只需添加新类 |
| 可读性 | 大量if-else | 业务代码一行调用 |
| 测试性 | 所有分支耦合 | 每个支付类可独立Mock |
| 维护成本 | 随时间指数增长 | 线性增长 |
最佳实践建议:
- 支付接口设计要合理:预留
support(String type)方法可让工厂更智能 - 结合Spring的IoC容器:让工厂成为Bean,自动注入所有支付实现
- 日志与监控:在工厂层统一记录创建日志
- 降级与兜底:工厂返回默认支付或抛出明确异常
重构不是炫技,而是用设计模式对抗软件熵增,当你的业务方说“下周要接入银联云闪付”时,你只需要微笑回答:“知道了,我会新建一个类。”——这就是工厂模式带给你的底气。