从“代码沼泽”到“设计典范”:一次烂代码重构与设计模式实战

代码重构艺术 3.4w人浏览 40人参与

序章:一座待重建的“烂尾楼”

深夜,我收到一份紧急代码评审请求。同事小李在聊天窗口哀嚎:“哥,这个订单模块我实在改不动了,加个优惠券功能已经卡了三天,一动就崩!”

我打开那个传说中的OrderService.java文件——一个高达1200行的类,没有注释,方法长度普遍超过100行,嵌套的if-else像俄罗斯套娃,业务逻辑和数据库操作、短信发送、日志打印全部搅在一起。更可怕的是,这个类已经被5个不同模块直接调用,任何修改都可能引发连锁反应。

// 原始烂代码示例(简化版)
public class OrderService {
    public String createOrder(Map<String, Object> params) {
        // 参数校验(60行)
        if (params.get("userId") == null) {
            log.error("用户ID为空");
            sendAlert("用户ID为空");
            return "失败";
        }
        // 业务校验(80行)
        User user = userDao.findById((Long)params.get("userId"));
        if (user == null) {
            // ... 类似逻辑重复十几次
        }
        // 价格计算(150行)
        double price = calculatePrice(params);
        // 库存检查(120行)
        // 订单创建(100行)
        // 支付处理(200行)
        // 日志记录(分散在各处)
        // 短信通知(穿插在异常处理中)
        // ... 总共1200行
    }
    
    // 其他15个类似长度的方法
}

这就是典型的“上帝类”反模式——一个类承担了太多职责,成为了系统的“单点故障”。今天,我将带大家见证这座“代码烂尾楼”如何通过设计模式,一步步重建成高内聚、低耦合、易扩展的现代化架构

第一幕:识别坏味道,制定重构策略

1.1 代码坏味道诊断清单

  • 过长的类和方法:一个类1200行,方法平均200行

  • 重复代码:参数校验、日志记录、异常处理在各处复制粘贴

  • 霰弹式修改:改一处业务逻辑需要修改十几个地方

  • 过度耦合:直接依赖DAO、短信服务、日志服务等具体实现

  • 条件逻辑爆炸:if-else嵌套超过5层,switch-case处理十几种类型

  • 数据泥团:多个方法接收相同的冗长参数列表

1.2 重构策略:分而治之,模式制胜

我们的重构将分四步走,每一步引入1-2个关键设计模式:

  1. 职责分离:运用策略模式工厂模式解耦业务逻辑

  2. 流程标准化:运用模板方法模式责任链模式规范处理流程

  3. 对象创建优化:运用建造者模式原型模式简化对象构建

  4. 行为扩展:运用观察者模式装饰器模式实现动态扩展

第二幕:重构实战——从混乱到秩序

2.1 第一步:分离变化点——策略模式 + 工厂模式

问题:价格计算逻辑有6种不同类型(普通、促销、团购、秒杀、会员、拼团),全部挤在一个500行的calculatePrice()方法中。

重构前

public double calculatePrice(Order order) {
    if (order.getType().equals("NORMAL")) {
        // 30行普通价格计算
    } else if (order.getType().equals("PROMOTION")) {
        // 40行促销价格计算
    } else if (order.getType().equals("GROUP_BUY")) {
        // 50行团购价格计算
    }
    // ... 另外3种类型
}

运用策略模式重构

// 1. 定义策略接口
public interface PriceStrategy {
    double calculate(Order order);
    boolean supports(OrderType type);
}

// 2. 实现具体策略
@Component
public class NormalPriceStrategy implements PriceStrategy {
    @Override
    public double calculate(Order order) {
        // 专注普通价格计算,仅15行
        return order.getBasePrice() * order.getQuantity();
    }
    
    @Override
    public boolean supports(OrderType type) {
        return OrderType.NORMAL == type;
    }
}

@Component 
public class PromotionPriceStrategy implements PriceStrategy {
    @Override
    public double calculate(Order order) {
        // 专注促销计算,仅20行
        double base = order.getBasePrice() * 0.9;
        if (order.getQuantity() > 10) {
            base *= 0.95;
        }
        return base * order.getQuantity();
    }
    
    @Override
    public boolean supports(OrderType type) {
        return OrderType.PROMOTION == type;
    }
}

// 3. 策略工厂
@Component
public class PriceStrategyFactory {
    private final Map<OrderType, PriceStrategy> strategyMap = new HashMap<>();
    
    public PriceStrategyFactory(List<PriceStrategy> strategies) {
        // Spring会自动注入所有PriceStrategy实现
        strategies.forEach(strategy -> {
            for (OrderType type : OrderType.values()) {
                if (strategy.supports(type)) {
                    strategyMap.put(type, strategy);
                    break;
                }
            }
        });
    }
    
    public PriceStrategy getStrategy(OrderType type) {
        return strategyMap.get(type);
    }
}

// 4. 精简后的价格计算服务
@Service
public class PriceCalculationService {
    private final PriceStrategyFactory factory;
    
    public double calculatePrice(Order order) {
        PriceStrategy strategy = factory.getStrategy(order.getType());
        return strategy.calculate(order);
    }
}

效果对比

  • ✅ 代码行数:从500+行减少到150行(所有策略类总和)

  • ✅ 可维护性:新增价格策略只需新增一个类,无需修改现有代码

  • ✅ 可测试性:每个策略可独立单元测试

  • ✅ 可读性:每个策略职责单一,逻辑清晰

2.2 第二步:规范处理流程——模板方法模式 + 责任链模式

问题:订单创建流程混乱,校验、计算、保存、通知等步骤随意穿插。

重构前

public String createOrder(OrderRequest request) {
    // 步骤1:校验(但有些校验在中间做)
    // 步骤2:计算价格(中间又做了一次库存校验)
    // 步骤3:扣库存(但失败后的回滚逻辑不完整)
    // 步骤4:保存订单(这里又校验了用户状态)
    // 步骤5:发短信(如果失败,订单已保存,状态不一致)
    // 步骤混乱,异常处理不一致
}

运用模板方法模式重构

// 1. 定义订单创建模板
public abstract class AbstractOrderCreator {
    
    // 模板方法:定义算法骨架
    public final Order createOrder(OrderRequest request) {
        preValidate(request);      // 前置校验
        Order order = buildOrder(request);  // 构建订单
        processBusiness(order);    // 业务处理
        saveOrder(order);          // 持久化
        postProcess(order);        // 后置处理
        return order;
    }
    
    // 基本步骤,子类必须实现
    protected abstract void preValidate(OrderRequest request);
    protected abstract Order buildOrder(OrderRequest request);
    protected abstract void processBusiness(Order order);
    
    // 可选步骤,提供默认实现
    protected void saveOrder(Order order) {
        orderRepository.save(order);
    }
    
    protected void postProcess(Order order) {
        // 默认无后置处理
    }
}

// 2. 具体订单创建器
@Service
public class NormalOrderCreator extends AbstractOrderCreator {
    @Override
    protected void preValidate(OrderRequest request) {
        // 普通订单的特定校验
        if (request.getUserId() == null) {
            throw new ValidationException("用户ID不能为空");
        }
        // ... 其他校验
    }
    
    @Override
    protected Order buildOrder(OrderRequest request) {
        return Order.builder()
                   .userId(request.getUserId())
                   .items(request.getItems())
                   .build();
    }
    
    @Override
    protected void processBusiness(Order order) {
        // 普通订单的业务处理
        inventoryService.deduct(order.getItems());
    }
    
    @Override
    protected void postProcess(Order order) {
        // 普通订单发送确认短信
        smsService.sendConfirm(order.getUserPhone());
    }
}

// 3. 结合责任链模式处理复杂校验
@Component
public class OrderValidationChain {
    private List<Validator> validators;
    
    public ValidationResult validate(OrderRequest request) {
        ValidationResult result = new ValidationResult();
        for (Validator validator : validators) {
            if (!validator.validate(request, result)) {
                break; // 任一验证失败则终止
            }
        }
        return result;
    }
}

// 校验器接口
public interface Validator {
    boolean validate(OrderRequest request, ValidationResult result);
}

// 具体校验器
@Component
@Order(1) // 定义校验顺序
public class UserValidator implements Validator {
    @Override
    public boolean validate(OrderRequest request, ValidationResult result) {
        if (request.getUserId() == null) {
            result.addError("用户不存在");
            return false;
        }
        return true;
    }
}

效果对比

  • ✅ 流程标准化:所有订单创建遵循相同流程骨架

  • ✅ 流程控制:父类控制流程,子类填充细节

  • ✅ 异常安全:模板方法可统一添加事务和异常处理

  • ✅ 复用性:公共步骤在父类中复用

2.3 第三步:优雅构建对象——建造者模式 + 原型模式

问题:Order对象有20+个字段,构造方法参数列表过长,且不同场景需要不同初始化。

重构前

// 构造函数灾难
Order order = new Order(userId, items, address, price, discount, 
                       coupon, remark, invoice, delivery, ...);

// 或者使用setter,但可能遗漏必填字段
Order order = new Order();
order.setUserId(userId);
// ...忘记设置其他10个必填字段

运用建造者模式重构

// 1. 建造者模式实现
public class Order {
    private final Long orderId;
    private final Long userId;
    private final List<OrderItem> items;
    private final Address address;
    private final BigDecimal totalAmount;
    // ... 其他字段
    
    // 私有构造,强制使用建造者
    private Order(Builder builder) {
        this.orderId = builder.orderId;
        this.userId = builder.userId;
        this.items = builder.items;
        this.address = builder.address;
        this.totalAmount = builder.totalAmount;
        // ... 其他字段
    }
    
    // 静态建造者方法
    public static Builder builder() {
        return new Builder();
    }
    
    // 建造者内部类
    public static class Builder {
        private Long orderId;
        private Long userId;
        private List<OrderItem> items = new ArrayList<>();
        private Address address;
        private BigDecimal totalAmount;
        
        public Builder orderId(Long orderId) {
            this.orderId = orderId;
            return this;
        }
        
        public Builder userId(Long userId) {
            this.userId = userId;
            return this;
        }
        
        // ... 其他字段的构建方法
        
        // 必填字段校验
        public Order build() {
            if (userId == null) {
                throw new IllegalStateException("用户ID不能为空");
            }
            if (items.isEmpty()) {
                throw new IllegalStateException("订单项不能为空");
            }
            return new Order(this);
        }
    }
}

// 2. 流畅的API使用
Order order = Order.builder()
                  .userId(123L)
                  .items(items)
                  .address(address)
                  .totalAmount(calculateTotal(items))
                  .build();

// 3. 结合原型模式快速克隆
public class Order implements Cloneable {
    // ... 其他代码
    
    @Override
    public Order clone() {
        try {
            Order cloned = (Order) super.clone();
            // 深拷贝可变对象
            cloned.items = new ArrayList<>(this.items);
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

// 创建相似订单
Order templateOrder = getOrderTemplate();
Order newOrder = templateOrder.clone()
                             .toBuilder()  // 假设有toBuilder方法
                             .orderId(generateId())
                             .createdTime(new Date())
                             .build();

2.4 第四步:动态扩展行为——观察者模式 + 装饰器模式

问题:订单状态变更时需要通知多个系统,硬编码导致耦合。

重构前

public void updateOrderStatus(Long orderId, OrderStatus status) {
    orderDao.updateStatus(orderId, status);
    
    // 硬编码的通知逻辑
    if (status == OrderStatus.PAID) {
        smsService.sendPaidNotification(orderId);
        emailService.sendReceipt(orderId);
        couponService.updateCouponStatus(orderId);
        inventoryService.updateInventory(orderId);
        // 每加一个通知点都要改这里
    }
}

运用观察者模式重构

// 1. 定义事件
public class OrderStatusChangedEvent {
    private final Long orderId;
    private final OrderStatus oldStatus;
    private final OrderStatus newStatus;
    private final LocalDateTime changeTime;
    
    // 建造者省略...
}

// 2. 事件发布者
@Service
public class OrderService {
    private final ApplicationEventPublisher eventPublisher;
    
    public void updateOrderStatus(Long orderId, OrderStatus newStatus) {
        OrderStatus oldStatus = orderDao.getStatus(orderId);
        orderDao.updateStatus(orderId, newStatus);
        
        // 发布事件,而不是直接调用
        eventPublisher.publishEvent(new OrderStatusChangedEvent(
            orderId, oldStatus, newStatus, LocalDateTime.now()
        ));
    }
}

// 3. 事件监听器
@Component
@Slf4j
public class OrderStatusChangeListeners {
    
    @EventListener
    @Async
    public void handlePaidEvent(OrderStatusChangedEvent event) {
        if (event.getNewStatus() == OrderStatus.PAID) {
            // 发送短信通知
            smsService.sendPaymentSuccess(event.getOrderId());
        }
    }
    
    @EventListener
    @Order(1) // 处理顺序
    public void handleShippedEvent(OrderStatusChangedEvent event) {
        if (event.getNewStatus() == OrderStatus.SHIPPED) {
            // 更新库存
            inventoryService.confirmDeduction(event.getOrderId());
        }
    }
    
    // 新增监听器只需添加新方法,无需修改原有代码
    @EventListener
    public void handleCompletedEvent(OrderStatusChangedEvent event) {
        if (event.getNewStatus() == OrderStatus.COMPLETED) {
            // 新增:订单完成时给用户加积分
            pointService.addPoints(event.getOrderId());
        }
    }
}

运用装饰器模式增强功能

// 1. 原始订单服务接口
public interface OrderService {
    Order createOrder(OrderRequest request);
    Order getOrder(Long orderId);
}

// 2. 基础实现
@Service
public class BasicOrderService implements OrderService {
    @Override
    public Order createOrder(OrderRequest request) {
        // 基础创建逻辑
        return orderRepository.save(convertToOrder(request));
    }
    
    @Override
    public Order getOrder(Long orderId) {
        return orderRepository.findById(orderId).orElse(null);
    }
}

// 3. 装饰器:添加缓存功能
@Service
@Primary // 让Spring优先注入这个装饰后的版本
public class CachedOrderService implements OrderService {
    private final OrderService delegate;
    private final CacheManager cacheManager;
    
    public CachedOrderService(BasicOrderService delegate, CacheManager cacheManager) {
        this.delegate = delegate;
        this.cacheManager = cacheManager;
    }
    
    @Override
    public Order createOrder(OrderRequest request) {
        Order order = delegate.createOrder(request);
        // 创建后清除相关缓存
        cacheManager.evict("orders", order.getUserId().toString());
        return order;
    }
    
    @Override
    @Cacheable(value = "orders", key = "#orderId")
    public Order getOrder(Long orderId) {
        // 缓存装饰:先查缓存,没有再查数据库
        return delegate.getOrder(orderId);
    }
}

// 4. 可以继续装饰:添加日志、监控、限流等
@Service
public class MonitoredOrderService implements OrderService {
    private final OrderService delegate;
    private final MeterRegistry meterRegistry;
    
    @Override
    public Order createOrder(OrderRequest request) {
        Timer.Sample sample = Timer.start(meterRegistry);
        try {
            return delegate.createOrder(request);
        } finally {
            sample.stop(Timer.builder("order.create.time")
                           .register(meterRegistry));
        }
    }
}

第三幕:重构成果与架构对比

3.1 重构前后架构对比图

重构前(单体架构):
┌─────────────────────────────────────┐
│           OrderService (1200行)      │
│  ├─ createOrder() 350行              │
│  ├─ calculatePrice() 500行           │
│  ├─ updateStatus() 200行             │
│  └─ 其他10+个方法                    │
│  直接依赖:UserDao, ProductDao,      │
│          SmsService, EmailService... │
└─────────────────────────────────────┘

重构后(领域驱动+模式组合):
┌─────────────────────────────────────────────┐
│               OrderFacade (门面)            │
├─────────────────────────────────────────────┤
│  OrderService (接口)                         │
│  ├─ CachedOrderService (装饰器)              │
│  │   └─ MonitoredOrderService (装饰器)       │
│  │       └─ BasicOrderService (实现)         │
├─────────────────────────────────────────────┤
│  OrderFactory (工厂)                         │
│  ├─ NormalOrderCreator (模板方法)            │
│  ├─ GroupOrderCreator (模板方法)             │
│  └─ 其他订单创建器                           │
├─────────────────────────────────────────────┤
│  PriceStrategyFactory (策略工厂)             │
│  ├─ NormalPriceStrategy (策略)               │
│  ├─ PromotionPriceStrategy (策略)            │
│  └─ 其他价格策略                             │
├─────────────────────────────────────────────┤
│  OrderValidationChain (责任链)               │
│  ├─ UserValidator                           │
│  ├─ InventoryValidator                      │
│  └─ 其他校验器                               │
├─────────────────────────────────────────────┤
│  EventPublisher (观察者模式)                 │
│  └─ 多个EventListener                        │
└─────────────────────────────────────────────┘

3.2 量化改进指标

指标重构前重构后改进率
单类最大行数1200行150行-87.5%
方法平均行数85行25行-70.6%
单元测试覆盖率15%85%+466%
新增功能平均耗时2-3天2-3小时-90%
认知复杂度极高中等-60%
圈复杂度458-82%

3.3 真实业务场景:添加优惠券功能

重构前(小李的噩梦)

// 需要修改OrderService的多个方法,涉及300+行代码
public String createOrder(OrderRequest request) {
    // ... 原有逻辑
    
    // 新增:优惠券处理(混杂在原有逻辑中)
    if (request.getCouponCode() != null) {
        Coupon coupon = couponDao.findByCode(request.getCouponCode());
        if (coupon == null) {
            log.error("优惠券不存在");
            // 但订单可能已经部分处理,需要回滚...
        }
        // 优惠券使用逻辑(50行)
        // 与价格计算逻辑耦合
        // 需要修改calculatePrice方法
    }
    
    // ... 更多修改
}

重构后(优雅扩展)

// 1. 新增优惠券策略(仅需新增一个类)
@Component
public class CouponPriceStrategy implements PriceStrategy {
    private final CouponService couponService;
    
    @Override
    public double calculate(Order order) {
        BigDecimal discount = couponService.calculateDiscount(order);
        return order.getBaseAmount() - discount.doubleValue();
    }
    
    @Override
    public boolean supports(OrderType type) {
        return OrderType.COUPON == type;
    }
}

// 2. 新增优惠券校验器
@Component
@Order(3)
public class CouponValidator implements Validator {
    @Override
    public boolean validate(OrderRequest request, ValidationResult result) {
        if (request.getCouponCode() != null) {
            Coupon coupon = couponService.validateCoupon(
                request.getCouponCode(), request.getUserId()
            );
            if (coupon == null) {
                result.addError("优惠券无效");
                return false;
            }
        }
        return true;
    }
}

// 3. 优惠券使用监听器
@Component
public class CouponUsageListener {
    @EventListener
    public void onOrderPaid(OrderStatusChangedEvent event) {
        if (event.getNewStatus() == OrderStatus.PAID) {
            couponService.markAsUsed(event.getOrderId());
        }
    }
}

// 完成!无需修改任何现有类

第四幕:重构心法与模式选择指南

4.1 设计模式选用决策树

遇到问题 → 判断类型 → 选择模式
    │
    ├─ 对象创建复杂? → 建造者/工厂/原型
    │
    ├─ 多个if-else判断类型? → 策略/状态
    │
    ├─ 流程固定但步骤可变? → 模板方法
    │
    ├─ 需要按顺序处理? → 责任链
    │
    ├─ 一变化需要通知多方? → 观察者
    │
    ├─ 需要动态添加功能? → 装饰器
    │
    └─ 简化复杂子系统访问? → 门面

4.2 重构黄金法则

  1. 小步快跑:每次重构不超过30分钟,频繁提交

  2. 测试守护:重构前先写测试,确保行为不变

  3. 模式不滥用:不是每个问题都需要模式,KISS原则优先

  4. 持续演进:架构不是一次设计出来的,而是演进出来的

4.3 常见反模式与纠正

  • 上帝类 → 单一职责原则 + 策略/工厂模式

  • 重复代码 → 模板方法/继承/组合

  • 霰弹式修改 → 观察者/事件驱动

  • 过度耦合 → 依赖注入 + 接口隔离

  • 条件爆炸 → 策略/状态/表驱动

终章:从技工到工匠的蜕变

三个月后,小李兴奋地告诉我:“哥,昨天产品经理临时加需求——支持七天无理由退货的逆向订单流程,我只用了2小时就上线了!就新增了一个RefundOrderCreator和几个策略类,完全没动老代码!”

这就是设计模式的魅力所在。它不只是解决眼前问题的工具,更是预防未来问题的智慧。通过这次重构,我们收获的不仅是:

  1. 可维护的代码:新人能在一天内理解模块

  2. 可扩展的架构:新需求平均开发时间减少70%

  3. 可靠的质量:bug率下降85%,测试覆盖率85%+

  4. 可复用的资产:价格策略、校验链等可复用于其他模块

但更重要的是,团队建立了对代码质量的信仰。我们开始主动识别坏味道,小步重构,持续改进。代码不再是负担,而是值得骄傲的资产。

烂代码是负债,好代码是资产。设计模式就是帮你将技术负债转为技术资产的最佳杠杆。下一次当你面对一团乱麻的代码时,不要绝望——拿起设计模式这把手术刀,勇敢地开始重构吧。

毕竟,每个优雅的系统,都曾是一团糟的代码。区别在于,有人选择了忍受,而有人选择了改变。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值