一、大型重构策略:梳理并分解继承体系、将过程化设计转化为对象设计、分离领域与表现层、提炼层次结构
大型重构,说白了就是给系统动大手术。我做了十几年架构,见过太多代码库从整洁变成一团乱麻。今天聊的这四个策略,是我在实际项目中反复用到的核心手段。
1. 梳理并分解继承体系
继承体系这东西,一开始看着挺美。子类继承父类,复用代码,多省事。但项目跑个两三年,你就会发现继承链越来越深,改一个基类,下面十几个子类全得跟着改。
我记得有个项目,继承深度达到了七层。最顶层的基类叫BaseEntity,底下有BusinessEntity、AuditEntity、VersionedEntity……到最后,新来的同事想加个字段,得先花两天搞清楚继承关系。
怎么分解?我一般分三步走:
- 识别"上帝基类"——那些被太多子类依赖的基类,优先处理
- 提取接口——把基类的行为抽象成接口,让子类各自实现
- 用组合替代继承——把公共逻辑拆成独立的服务类,通过依赖注入组合进来
举个例子,原来可能是这样:
// 重构前:继承体系
public class BaseRepository {
protected Connection getConnection() { ... }
protected void logQuery(String sql) { ... }
}
public class UserRepository extends BaseRepository {
public User findById(int id) {
Connection conn = getConnection();
logQuery("SELECT * FROM users WHERE id = " + id);
// ...
}
}
重构后,变成这样:
// 重构后:组合替代继承
public class UserRepository {
private final DatabaseService dbService;
private final AuditService auditService;
public UserRepository(DatabaseService db, AuditService audit) {
this.dbService = db;
this.auditService = audit;
}
public User findById(int id) {
Connection conn = dbService.getConnection();
auditService.logQuery("SELECT * FROM users WHERE id = " + id);
// ...
}
}
2. 将过程化设计转化为对象设计
过程化设计,就是那种一个函数几百行,全是if-else和switch-case。你想想看,这种代码改起来多痛苦?加一个条件,得翻遍整个函数,生怕漏掉某个分支。
我曾经接手过一个支付系统,核心逻辑全写在一个PaymentProcessor类里,光process()方法就八百多行。里面处理了支付宝、微信、银联、PayPal……十几种支付方式。每次加新支付渠道,都得在这个方法里加一段if,测试覆盖率还特别低。
怎么转成对象设计?核心思路是把行为封装到对象里:
- 识别出不同的"行为变体"——比如不同的支付方式
- 为每种变体创建一个类,实现统一的接口
- 用工厂或策略模式来选择合适的实现
重构后的代码大概是这样的:
// 策略模式:每种支付方式一个类
public interface PaymentStrategy {
PaymentResult pay(Order order);
}
public class AlipayStrategy implements PaymentStrategy {
public PaymentResult pay(Order order) {
// 支付宝特有的逻辑
}
}
public class WechatStrategy implements PaymentStrategy {
public PaymentResult pay(Order order) {
// 微信支付特有的逻辑
}
}
// 使用方只需要知道接口
public class PaymentService {
private final Map<String, PaymentStrategy> strategies;
public PaymentResult process(Order order, String channel) {
PaymentStrategy strategy = strategies.get(channel);
if (strategy == null) {
throw new UnsupportedPaymentException(channel);
}
return strategy.pay(order);
}
}
if-else反而更清晰。我见过有人把三个分支硬拆成五个类,结果代码更难懂了。
3. 分离领域与表现层
这个问题太常见了。很多项目一开始图省事,把业务逻辑直接写在控制器里。比如Spring MVC的Controller里,既有HTTP请求处理,又有数据库查询,还有业务规则校验。
我有个朋友的项目,Controller里直接写了SQL语句。你想想看,这要是换个数据库,得改多少个地方?
分离的核心是分层架构:
| 层次 | 职责 | 常见问题 |
|---|---|---|
| 表现层 | 处理HTTP请求、参数校验、视图渲染 | 混入业务逻辑、直接操作数据库 |
| 应用层 | 编排业务用例、事务管理 | 过于臃肿、职责不清 |
| 领域层 | 核心业务规则、实体、值对象 | 被贫血模型替代、逻辑散落 |
| 基础设施层 | 数据库访问、外部服务调用 | 与领域层耦合过紧 |
重构时,我一般从识别"胖Controller"开始。如果一个Controller里超过50行业务逻辑,就该拆了。
// 重构前:Controller里混了业务逻辑
@RestController
public class OrderController {
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
// 参数校验
if (request.getAmount() <= 0) {
throw new IllegalArgumentException("金额必须大于0");
}
// 业务逻辑:计算折扣
double discount = 0;
if (request.getAmount() > 1000) {
discount = 0.1;
}
// 数据库操作
Order order = new Order();
order.setAmount(request.getAmount() * (1 - discount));
orderRepository.save(order);
return order;
}
}
// 重构后:Controller只负责HTTP处理
@RestController
public class OrderController {
private final OrderService orderService;
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
return orderService.createOrder(request);
}
}
// 领域服务处理业务逻辑
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final DiscountCalculator discountCalculator;
public Order createOrder(OrderRequest request) {
request.validate(); // 参数校验
double discount = discountCalculator.calculate(request.getAmount());
Order order = new Order(request, discount);
return orderRepository.save(order);
}
}
4. 提炼层次结构
这个策略,说白了就是给代码"分层"。很多系统一开始没有明确的层次,所有代码混在一起。时间一长,你想改个功能,得先花半小时搞清楚代码在哪儿。
我常用的分层模式是四层架构:
- 入口层:接收外部请求,做最基础的校验
- 编排层:协调多个领域服务,处理事务
- 领域层:核心业务逻辑,不依赖外部框架
- 基础设施层:数据库、消息队列、外部API
这里有个关键点:依赖方向必须单向。上层可以依赖下层,下层绝不能依赖上层。我见过一个项目,领域层里直接引用了Spring的@Autowired注解,结果想换个框架,整个领域层都得重写。
提炼层次结构时,我一般从最底层开始。先把基础设施层的代码抽出来,确保它们不依赖上层。然后逐步往上提炼。这样做的好处是,底层稳定了,上层再怎么改,底层都不用动。
嗯,这里要注意:别一次提炼太多层。我见过有人一口气提炼了七层,结果每层之间只有薄薄的一层封装,反而增加了复杂度。一般来说,三到四层就够用了。
这张图展示的就是典型的四层依赖关系。箭头方向表示依赖方向,上层依赖下层,下层对上层一无所知。这样做的好处是,你想换数据库?只需要改基础设施层,领域层完全不用动。
好了,这四个策略讲完了。总结一下:
- 分解继承体系:用组合替代继承,减少耦合
- 过程化转对象设计:把行为封装到对象里,用策略模式替代大
if-else - 分离领域与表现层:Controller只做HTTP处理,业务逻辑交给领域服务
- 提炼层次结构:明确分层,依赖方向单向,每层职责清晰
这些策略不是银弹,但在我经历过的项目中,它们确实帮了大忙。你想想看,如果你的代码库能按照这些原则重构一遍,维护成本至少能降一半。