本文目录导读:

- 原始代码(问题所在)
- 第一次重构:使用
策略模式解决分支爆炸 - 第二次重构:策略模式 + 简单工厂(解决客户端耦合)
- 第三次重构:策略模式 + 简单工厂 + 反射/注册表(解决工厂类修改)
- 第四次重构:引入装饰者模式(增强功能)
- 最终架构总览(UML 关系)
- 重构的思路演变
我将从一个原始代码出发,逐步展示如何重构到设计模式,让你清晰看到从“烂代码”转型为“优雅架构”的过程。
我们以经典的支付系统为例,从策略模式 出发,逐步叠加设计模式。
原始代码(问题所在)
假设我们有一个支付服务,一开始只有微信和支付宝:
public class PaymentService {
public void pay(String type, double amount) {
if ("wechat".equals(type)) {
System.out.println("使用微信支付:" + amount + "元");
// 大量微信逻辑:生成二维码、调用微信API...
} else if ("alipay".equals(type)) {
System.out.println("使用支付宝支付:" + amount + "元");
// 大量支付宝逻辑:签名、调用支付宝API...
} else {
// 新增银行卡支付?又要增加一个 else-if
throw new RuntimeException("不支持的支付方式");
}
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
PaymentService service = new PaymentService();
service.pay("wechat", 100.0);
service.pay("alipay", 200.0);
// 如果现在要加"银行卡"支付,需要去修改 PaymentService 类
}
}
痛点: 违反了 OCP(开闭原则),每次新增支付方式都要侵入原有代码,代码膨胀后难以维护。
第一次重构:使用 策略模式 解决分支爆炸
核心思想: 把算法(支付方式) 封装成独立的类,客户端选择策略。
定义策略接口
// 策略接口:所有支付方式的统一契约
public interface PaymentStrategy {
void pay(double amount); // 所有支付方式都必须实现这个行为
}
实现具体策略(算法族)
// 具体策略A:微信支付
public class WechatPay implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
// 微信专属复杂逻辑
}
}
// 具体策略B:支付宝支付
public class AlipayPay implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
// 支付宝专属复杂逻辑
}
}
// 新增策略C:银行卡支付(不再修改旧类,直接新增类)
public class BankCardPay implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用银行卡支付:" + amount + "元");
// 银行卡复杂逻辑
}
}
上下文类(持有策略引用)
// 上下文:负责将请求委托给指定的策略对象
public class PaymentContext {
private PaymentStrategy strategy; // 核心:持有策略接口
// 通过构造器或Setter注入具体策略
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePay(double amount) {
strategy.pay(amount); // 委托调用
}
}
客户端使用(策略模式)
public class Client {
public static void main(String[] args) {
// 不再写 if-else,直接选择策略对象
PaymentContext context = new PaymentContext(new WechatPay());
context.executePay(100.0);
// 想换支付宝?直接换策略
context = new PaymentContext(new AlipayPay());
context.executePay(200.0);
// 新增银行卡?客户端选择新策略即可
context = new PaymentContext(new BankCardPay());
context.executePay(300.0);
}
}
成果:
- 完全消除 if-else。
- 新增支付方式 = 新增一个类,零修改原有代码(满足开闭原则)。
- 策略可以运行时动态替换。
第二次重构:策略模式 + 简单工厂(解决客户端耦合)
新问题: 客户端现在直接 new 具体策略类,客户端仍然依赖具体策略,如果我们希望客户端只传一个字符串(如"wechat")就能拿到对应策略,就需要引入简单工厂。
创建策略工厂
public class PaymentFactory {
// 静态工厂方法:根据类型返回策略
public static PaymentStrategy getPaymentStrategy(String type) {
switch (type) {
case "wechat":
return new WechatPay();
case "alipay":
return new AlipayPay();
case "bank":
return new BankCardPay();
default:
throw new IllegalArgumentException("不支持的支付类型:" + type);
}
}
}
升级后的客户端(客户端更傻瓜)
public class Client {
public static void main(String[] args) {
// 将判断的逻辑下沉到工厂,客户端不依赖具体类
String payType = "alipay"; // 从配置/前端获取
PaymentStrategy strategy = PaymentFactory.getPaymentStrategy(payType);
PaymentContext context = new PaymentContext(strategy);
context.executePay(500.0);
}
}
成果: 客户端只依赖工厂接口,进一步解耦了客户端与具体策略的依赖。
第三次重构:策略模式 + 简单工厂 + 反射/注册表(解决工厂类修改)
新问题: 工厂内部依然有 switch(或 if-else),新增支付方式要修改工厂类,还是不符合开闭原则,如何做到工厂也“零修改”?
方案: 使用 反射 + 配置文件 或 注册表模式(Map>)。
使用反射 + 配置文件(彻底解耦)
配置文件 payment.properties:
wechat=com.example.WechatPay alipay=com.example.AlipayPay bank=com.example.BankCardPay
重构工厂(通过反射读取配置)
import java.io.InputStream;
import java.util.Properties;
public class PaymentFactory {
private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>();
static {
// 读取配置文件
try (InputStream input = PaymentFactory.class.getClassLoader()
.getResourceAsStream("payment.properties")) {
Properties prop = new Properties();
prop.load(input);
// 利用反射创建实例
for (String key : prop.stringPropertyNames()) {
String className = prop.getProperty(key);
Class<?> clazz = Class.forName(className);
PaymentStrategy strategy = (PaymentStrategy) clazz.getDeclaredConstructor().newInstance();
STRATEGY_MAP.put(key, strategy);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static PaymentStrategy getPaymentStrategy(String type) {
return STRATEGY_MAP.get(type);
}
}
成果:
- 工厂类永不修改,新增支付方式只需新增类 + 在配置文件加一行。
- 这是从“硬编码”向“元数据驱动”的架构演进。
第四次重构:引入装饰者模式(增强功能)
新需求: 支付时要做日志记录、事务控制、安全检查等横切关注点,如果直接改策略类,会破坏单一职责。
方案: 使用 装饰者模式 将增强功能动态地包装在策略对象上。
基础策略不变
创建装饰者抽象类
// 装饰者基类:同样实现策略接口,并持有被包装的策略
public abstract class PaymentDecorator implements PaymentStrategy {
protected PaymentStrategy wrappedStrategy; // 持有被装饰的对象
public PaymentDecorator(PaymentStrategy strategy) {
this.wrappedStrategy = strategy;
}
@Override
public void pay(double amount) {
// 默认委托,子类可选择增强或替换
wrappedStrategy.pay(amount);
}
}
创建具体装饰者(增强功能)
// 具体装饰者1:日志记录
public class LoggingDecorator extends PaymentDecorator {
public LoggingDecorator(PaymentStrategy strategy) {
super(strategy);
}
@Override
public void pay(double amount) {
System.out.println("[日志开始] 正在支付...");
long start = System.currentTimeMillis();
super.pay(amount); // 调用原始支付逻辑
long end = System.currentTimeMillis();
System.out.println("[日志结束] 支付耗时:" + (end - start) + "ms");
}
}
// 具体装饰者2:安全检查(腾讯云、阿里云安全风控)
public class SecurityDecorator extends PaymentDecorator {
public SecurityDecorator(PaymentStrategy strategy) {
super(strategy);
}
@Override
public void pay(double amount) {
System.out.println("[安全检测] 进行风险认证...");
super.pay(amount);
System.out.println("[安全检测] 认证通过");
}
}
客户端:动态组合装饰
public class Client {
public static void main(String[] args) {
// 原始策略(微信付款)
PaymentStrategy strategy = PaymentFactory.getPaymentStrategy("wechat");
// 动态增强:先套日志,再套安全
PaymentStrategy decorated = new SecurityDecorator(new LoggingDecorator(strategy));
PaymentContext context = new PaymentContext(decorated);
context.executePay(1000.0);
}
}
成果:
- 策略类保持单一职责(纯粹的业务逻辑)。
- 日志、安全等可以任意 组合、叠放,不修改原类。
- 符合“高内聚,低耦合”。
最终架构总览(UML 关系)
PaymentStrategy (接口) <--------------- PaymentsDecorator (抽象装饰者)
↑ ↑
| |
WechatPay | AlipayPay | BankCardPay LoggingDecorator | SecurityDecorator
客户端 (Client) --> PaymentContext --> PaymentStrategy
|
v
PaymentFactory (工厂,使用反射+注册表)
各模式的核心定位: | 模式 | 解决的问题 | | :--- | :--- | | 策略模式 | 将算法族封装,消除 if-else,行为可切换。 | | 简单工厂/注册表 | 将“创建算法”的过程解耦,客户端不依赖具体类。 | | 反射+配置文件 | 让工厂也完全满足开闭原则,支持动态扩展。 | | 装饰者模式 | 不修改策略类,动态给策略增加额外职责(日志、安全、缓存等)。 |
重构的思路演变
- 从乱到清: 用策略模式干掉最难看的 if-else。
- 从清到耦: 用工厂隐藏策略的创建细节,客户端不依赖具体策略。
- 从耦到活: 用反射+配置让工厂也具备扩展性,真正达到“永远不改老代码”。
- 从活到健: 用装饰者把业务外的横切逻辑剥离出来,让业务代码具备“层层打包”的能力。
通过这个案例,你可以看到:设计模式不是堆砌类,而是应对变化、理清职责的重要工具——经典设计模式组合使用往往能产生更强大的架构效果。
如果你目前有类似的、想重构的“烂代码”,可以发给我,我们一起拆解并重构到对应的设计模式!