
⭐️个体主页:Kidd
📚所属栏目:java

在上一篇实战中,我们基于接口与多态实现了简易支付系统,具备了基础支付、退款功能及良好的扩展性。但在实际开发场景中,仍存在可优化空间:客户端需直接创建具体支付类对象,耦合了具体实现;支付方式切换时需手动注入实例,缺乏统一管理。本文将结合工厂模式与策略模式,对原有支付系统进行升级,进一步降低耦合、提升代码灵活性与可维护性,深化面向对象设计思维的落地。
一、设计模式选型:工厂模式+策略模式
针对原有系统的不足,我们选用两种经典设计模式组合优化,两者分工明确、互补增效:
1.1 工厂模式:封装对象创建逻辑
工厂模式(Factory Pattern)的核心是"封装对象创建过程",由工厂类统一负责创建具体实例,客户端无需关注对象创建的细节,只需通过工厂获取所需实例。适用于解决"对象创建与业务逻辑耦合"问题,对应原有系统中"客户端直接new具体支付类"的痛点。
1.2 策略模式:封装算法(支付方式)家族
策略模式(Strategy Pattern)的核心是"定义一系列算法,将每个算法封装起来,使它们可以相互替换"。通过将不同支付方式(算法)抽象为策略,客户端可根据需求动态切换策略,无需修改原有业务逻辑,与原有系统的多态特性完美契合,同时优化支付方式的管理与切换逻辑。
1.3 组合优势
工厂模式负责"策略对象的创建",策略模式负责"策略的定义、切换与执行",两者结合可实现:客户端无需依赖具体支付类,通过工厂获取策略实例,通过上下文切换策略,完全隔离对象创建与业务执行,符合"开闭原则"与"单一职责原则"。
二、系统优化实现步骤
本次优化基于上一篇的支付系统核心代码(Payment接口、PaymentParam类、各支付实现类),新增工厂类、策略上下文类,调整客户端调用逻辑,不修改原有核心业务逻辑,保证兼容性。
2.1 定义支付方式枚举:统一标识策略
新增支付方式枚举(PayTypeEnum),用于统一标识不同支付策略,避免客户端直接传入字符串导致的错误,同时简化工厂类的逻辑判断。
Plain
/**
* 支付方式枚举:统一标识支付策略
*/
public enum PayTypeEnum {
ALIPAY("支付宝支付"),
WECHAT_PAY("微信支付"),
BANK_CARD_PAY("银行卡支付"),
UNION_PAY("银联支付");
// 支付方式描述
private final String desc;
PayTypeEnum(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
2.2 实现支付策略工厂:封装对象创建
创建支付策略工厂类(PaymentFactory),根据支付方式枚举创建对应支付实例,客户端通过工厂获取实例,无需直接依赖具体支付类。
Plain
/**
* 支付策略工厂:负责创建具体支付策略实例
*/
public class PaymentFactory {
// 私有构造:防止实例化工厂类
private PaymentFactory() {}
// 根据支付方式枚举创建对应支付实例
public static Payment getPayment(PayTypeEnum payType) {
switch (payType) {
case ALIPAY:
return new Alipay();
case WECHAT_PAY:
return new WeChatPay();
case BANK_CARD_PAY:
return new BankCardPay();
case UNION_PAY:
return new UnionPay();
default:
throw new IllegalArgumentException("不支持的支付方式:" + payType);
}
}
}
核心优势:若新增支付方式,只需扩展枚举与工厂类的switch分支,客户端调用逻辑无需修改;避免了客户端直接创建具体类,降低耦合。
2.3 优化支付上下文:适配策略模式
对上一篇的PaymentContext进行优化,使其适配策略模式,支持通过支付方式枚举切换策略,同时整合支付参数校验、支付/退款执行逻辑,强化上下文的统一调度能力。
Plain
/**
* 支付策略上下文:统一调度支付策略,支持动态切换
*/
public class PaymentStrategyContext {
// 持有支付策略引用
private Payment payment;
// 构造方法:通过工厂创建策略实例
public PaymentStrategyContext(PayTypeEnum payType) {
this.payment = PaymentFactory.getPayment(payType);
}
// 动态切换支付策略
public void switchStrategy(PayTypeEnum payType) {
this.payment = PaymentFactory.getPayment(payType);
System.out.println("支付方式切换为:" + payType.getDesc());
}
// 统一支付入口:整合参数校验与支付执行
public String executePay(PaymentParam param) {
// 前置参数校验
if (!Payment.validateParam(param)) {
return "支付失败:支付参数不合法";
}
// 执行具体支付策略
return payment.pay(param);
}
// 统一退款入口
public String executeRefund(PaymentParam param) {
if (!Payment.validateParam(param)) {
return "退款失败:参数不合法";
}
return payment.refund(param);
}
}
优化点:上下文不再需要客户端注入支付实例,而是通过工厂自动获取;新增策略切换方法,支持通过枚举快速切换支付方式;前置参数校验逻辑统一整合,减少重复代码。
三、优化后系统测试与验证
创建测试类,模拟客户端调用优化后的支付系统,验证策略创建、切换、支付/退款功能的正确性,对比原有系统体现优化价值。
Plain
/**
* 优化后支付系统测试类(工厂模式+策略模式)
*/
public class OptimizedPaymentSystemTest {
public static void main(String[] args) {
// 1. 初始化支付上下文(指定支付方式,工厂自动创建策略)
PaymentStrategyContext context = new PaymentStrategyContext(PayTypeEnum.ALIPAY);
// 支付宝支付测试
PaymentParam alipayParam = new PaymentParam("ORDER2024001", 199.99, "zhangsan@aliyun.com", "123456");
System.out.println(context.executePay(alipayParam));
System.out.println(context.executeRefund(alipayParam));
System.out.println("------------------------");
// 2. 切换支付方式为微信支付
context.switchStrategy(PayTypeEnum.WECHAT_PAY);
PaymentParam weChatParam = new PaymentParam("ORDER2024002", 299.00, "wx123456789", "654321");
System.out.println(context.executePay(weChatParam));
System.out.println("------------------------");
// 3. 切换支付方式为银联支付
context.switchStrategy(PayTypeEnum.UNION_PAY);
PaymentParam unionPayParam = new PaymentParam("ORDER2024004", 399.00, "6217001234567890", "333444");
System.out.println(context.executePay(unionPayParam));
System.out.println("------------------------");
// 4. 测试不支持的支付方式
try {
new PaymentStrategyContext(PayTypeEnum.valueOf("APPLE_PAY"));
} catch (IllegalArgumentException e) {
System.out.println("异常提示:" + e.getMessage());
}
}
}
测试结果与分析
Plain
支付宝支付成功!订单号:ORDER2024001,金额:199.99元,支付账号:zhangsan@aliyun.com
支付宝退款成功!订单号:ORDER2024001,退款金额:199.99元
------------------------
支付方式切换为:微信支付
微信支付成功!订单号:ORDER2024002,金额:299.00元,微信号:wx123456789
------------------------
支付方式切换为:银联支付
银联支付成功!订单号:ORDER2024004,金额:399.00元,银联卡号:6217001234567890
------------------------
异常提示:不支持的支付方式:APPLE_PAY
结果分析:优化后系统正常支持各类支付、退款功能,支付方式切换更简洁;客户端无需直接创建具体支付类,仅通过枚举与上下文交互,耦合度显著降低;工厂模式统一管理对象创建,策略模式实现算法灵活切换,代码可读性与可维护性大幅提升。
四、新旧系统对比:优化价值凸显
通过工厂模式与策略模式的整合,系统在以下维度实现显著优化,更贴合实际开发需求:
| 对比维度 | 原有系统 | 优化后系统 |
|---|---|---|
| 对象创建 | 客户端直接new具体支付类,耦合度高 | 工厂统一创建实例,客户端无感知具体实现 |
| 支付方式切换 | 手动注入新实例,需关注具体类名 | 通过枚举切换,上下文自动适配,简洁高效 |
| 代码冗余 | 参数校验逻辑分散在各支付类 | 上下文统一前置校验,减少重复代码 |
| 扩展性 | 新增支付类后,客户端需修改创建逻辑 | 仅扩展枚举与工厂分支,客户端无感知 |
五、进阶拓展:工厂模式的进一步优化
当前工厂类采用switch分支判断支付方式,若支付方式过多,分支会变得冗长,可进一步优化为"反射工厂",通过配置文件或注解动态加载支付类,彻底消除switch分支,实现更极致的扩展性。
Plain
/**
* 反射优化版支付工厂:消除switch分支,支持动态扩展
*/
public class ReflectPaymentFactory {
private ReflectPaymentFactory() {}
// 配置支付方式与对应类路径(实际可放在配置文件中)
private static final Map<PayTypeEnum, String> PAY_CLASS_MAP = new HashMap<>();
// 静态代码块初始化配置
static {
PAY_CLASS_MAP.put(PayTypeEnum.ALIPAY, "com.payment.Alipay");
PAY_CLASS_MAP.put(PayTypeEnum.WECHAT_PAY, "com.payment.WeChatPay");
PAY_CLASS_MAP.put(PayTypeEnum.BANK_CARD_PAY, "com.payment.BankCardPay");
PAY_CLASS_MAP.put(PayTypeEnum.UNION_PAY, "com.payment.UnionPay");
}
// 反射创建支付实例
public static Payment getPayment(PayTypeEnum payType) {
String className = PAY_CLASS_MAP.get(payType);
if (className == null) {
throw new IllegalArgumentException("不支持的支付方式:" + payType);
}
try {
// 反射加载类并创建实例
Class<?> clazz = Class.forName(className);
return (Payment) clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException("创建支付实例失败", e);
}
}
}
优化优势:新增支付方式时,只需添加枚举、配置类路径,无需修改工厂类代码,完全符合"开闭原则";适用于支付方式频繁扩展的场景,灵活性更强。
六、核心总结
本次通过工厂模式与策略模式对支付系统的优化,本质是对面向对象"封装、多态"特性的深度应用,核心价值在于:
-
工厂模式隔离了"对象创建"与"业务逻辑",降低了客户端与具体实现的耦合,简化了对象管理。
-
策略模式将不同支付方式封装为独立策略,实现了算法的动态切换与复用,提升了系统的灵活性。
-
两种模式的组合的并非过度设计,而是针对实际业务痛点的合理优化,使系统更符合企业级开发的规范与需求。
这种设计思路可广泛迁移到日志框架、消息通知、数据解析等多算法场景,通过设计模式的合理运用,将面向对象知识点转化为可落地的高质量代码,提升系统的可扩展性、可维护性与可读性。