设计模式学了不用等于没学。整理一下实际项目中真的用到的 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 项目里出现频率最高,其他模式(工厂、代理、装饰器、适配器)用到的时候再查。