设计模式实战,这 5 个最常用

15 阅读3分钟

设计模式学了不用等于没学。整理一下实际项目中真的用到的 5 个模式,不是教科书上的抽象例子,是代码里实际出现的场景。

1. 策略模式 — 消灭 if-else

场景:不同会员等级有不同的折扣计算逻辑。

// 差:一堆 if-else
public double getDiscount(String level, double price) {
    if ("VIP".equals(level)) {
        return price * 0.8;
    } else if ("SVIP".equals(level)) {
        return price * 0.6;
    } else if ("NORMAL".equals(level)) {
        return price * 0.95;
    }
    return price;
}

// 好:策略模式
public interface DiscountStrategy {
    double calculate(double price);
}

@Component("VIP")
public class VipDiscount implements DiscountStrategy {
    public double calculate(double price) { return price * 0.8; }
}

@Component("SVIP")
public class SvipDiscount implements DiscountStrategy {
    public double calculate(double price) { return price * 0.6; }
}

@Component("NORMAL")
public class NormalDiscount implements DiscountStrategy {
    public double calculate(double price) { return price * 0.95; }
}

@Service
public class PriceService {
    @Autowired
    private Map<String, DiscountStrategy> strategyMap;  // Spring 自动注入

    public double getPrice(String level, double price) {
        DiscountStrategy strategy = strategyMap.get(level);
        if (strategy == null) return price;
        return strategy.calculate(price);
    }
}

新增等级只需要加一个类,不用改 PriceService。

2. 观察者模式 — 事件驱动

场景:用户下单后要发通知、加积分、更新库存——但这些不应该耦合在订单逻辑里。

// 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
    private final Order order;
    public OrderCreatedEvent(Object source, Order order) {
        super(source);
        this.order = order;
    }
    public Order getOrder() { return order; }
}

// 发布事件
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void createOrder(OrderDTO dto) {
        Order order = orderMapper.insert(dto);
        // 发布事件,不关心谁在监听
        publisher.publishEvent(new OrderCreatedEvent(this, order));
    }
}

// 监听事件(各模块独立处理)
@Component
public class NotificationListener {
    @EventListener
    public void onOrderCreated(OrderCreatedEvent event) {
        notificationService.sendConfirmation(event.getOrder());
    }
}

@Component
public class PointsListener {
    @EventListener
    public void onOrderCreated(OrderCreatedEvent event) {
        pointsService.addPoints(event.getOrder().getUserId(), 100);
    }
}

Spring 的 @EventListener 就是观察者模式。订单服务只管发事件,通知、积分各自监听,互不干扰。

3. 模板方法模式 — 固定流程,变化步骤

场景:导出报表,Excel 和 PDF 的流程一样(查数据 → 格式化 → 写文件),但每一步的实现不同。

public abstract class ReportExporter {

    // 模板方法:定义固定流程
    public final void export(String reportId, String outputPath) {
        List<Record> data = queryData(reportId);
        byte[] formatted = format(data);
        writeToFile(formatted, outputPath);
    }

    // 子类实现具体步骤
    protected abstract List<Record> queryData(String reportId);
    protected abstract byte[] format(List<Record> data);

    private void writeToFile(byte[] content, String path) {
        // 公共逻辑:写文件
        try (FileOutputStream fos = new FileOutputStream(path)) {
            fos.write(content);
        } catch (IOException e) {
            throw new RuntimeException("写入失败", e);
        }
    }
}

public class ExcelExporter extends ReportExporter {
    protected List<Record> queryData(String reportId) {
        return reportMapper.selectAll(reportId);
    }
    protected byte[] format(List<Record> data) {
        // Excel 格式化逻辑
        return excelBytes;
    }
}

public class PdfExporter extends ReportExporter {
    protected List<Record> queryData(String reportId) {
        return reportMapper.selectAll(reportId);
    }
    protected byte[] format(List<Record> data) {
        // PDF 格式化逻辑
        return pdfBytes;
    }
}

流程固定(查 → 格式化 → 写文件),具体实现由子类决定。

4. 建造者模式 — 复杂对象构建

场景:一个配置类有十几个字段,不是每个都需要设。

// 差:构造函数参数太多
new HttpClient(5000, 3000, 3, true, "UTF-8", null, null, ...);

// 好:Builder 模式
HttpClient client = HttpClient.builder()
    .connectTimeout(5000)
    .readTimeout(3000)
    .maxRetries(3)
    .enableRetry(true)
    .charset("UTF-8")
    .build();

Lombok 的 @Builder 一行搞定:

@Builder
@Data
public class HttpClient {
    private int connectTimeout;
    private int readTimeout;
    private int maxRetries;
    private boolean enableRetry;
    private String charset;
}

5. 责任链模式 — 多级校验

场景:订单提交前要做一堆校验(参数校验 → 库存校验 → 价格校验 → 风控校验)。

public interface OrderValidator {
    void validate(OrderDTO dto);
}

@Component
@Order(1)
public class ParamValidator implements OrderValidator {
    public void validate(OrderDTO dto) {
        if (dto.getSkuId() == null) throw new BusinessException("SKU 不能为空");
    }
}

@Component
@Order(2)
public class StockValidator implements OrderValidator {
    public void validate(OrderDTO dto) {
        if (!inventoryService.hasStock(dto.getSkuId())) {
            throw new BusinessException("库存不足");
        }
    }
}

@Component
@Order(3)
public class RiskValidator implements OrderValidator {
    public void validate(OrderDTO dto) {
        if (riskService.isRisky(dto.getUserId())) {
            throw new BusinessException("风控拦截");
        }
    }
}

@Service
public class OrderService {
    @Autowired
    private List<OrderValidator> validators;  // Spring 按 @Order 排序

    public void createOrder(OrderDTO dto) {
        for (OrderValidator validator : validators) {
            validator.validate(dto);  // 任何一个校验失败就抛异常
        }
        // 全部通过,创建订单
    }
}

新增校验规则只需要加一个类,不用改 OrderService。

总结

模式解决的问题核心思想
策略大量 if-else把每个分支抽成类
观察者模块间强耦合事件发布/订阅
模板方法流程固定步骤不同父类定义骨架,子类实现细节
建造者构造函数参数太多链式调用构建对象
责任链多级校验/处理每个处理器各司其职

这 5 个在 Spring 项目里出现频率最高,其他模式(工厂、代理、装饰器、适配器)用到的时候再查。