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

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

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

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

java 复制代码
// 差:一堆 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. 观察者模式 --- 事件驱动

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

java 复制代码
// 定义事件
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 的流程一样(查数据 → 格式化 → 写文件),但每一步的实现不同。

java 复制代码
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. 建造者模式 --- 复杂对象构建

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

java 复制代码
// 差:构造函数参数太多
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 一行搞定:

java 复制代码
@Builder
@Data
public class HttpClient {
    private int connectTimeout;
    private int readTimeout;
    private int maxRetries;
    private boolean enableRetry;
    private String charset;
}

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

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

java 复制代码
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 项目里出现频率最高,其他模式(工厂、代理、装饰器、适配器)用到的时候再查。

相关推荐
Carl_奕然3 小时前
【智能体】Agent的四种设计模式之:Multi-Agent Collaboration
设计模式
Lost of 程序猿3 小时前
建造者模式实战:告别“十参数构造函数“的数据导出任务
后端·设计模式·c#·asp.net
SL_staff3 小时前
合规性折旧:当知识资产因主权缺位在审计中‘功能性清零’
java·设计模式·开源
Zane19948 小时前
工厂方法一定比简单工厂高级?三种工厂模式到底该怎么选
设计模式
Hespethorn8 小时前
设计模式是语言缺陷的补丁 —— 从工厂、单例、策略三个模式说起
设计模式
Lost of 程序猿8 小时前
命令模式实战:把“下单后的动作“打包成可执行的任务
后端·设计模式·c#·asp.net·命令模式
一只旭宝8 小时前
【C++复习】四种类型转换 + 常见设计模式 + Redis/MySQL(后端面试复习完整版)
c++·redis·笔记·mysql·设计模式
YYYing.10 小时前
【设计模式系列 (四) 】建造者模式
c++·后端·设计模式·建造者模式·c/c++
Zane19941 天前
同一段单例代码,为什么在高并发下偶尔会创建出两个实例?聊聊哪种单例实现才是真的安全
设计模式