设计模式的本质:隔离变化
一、为什么要学设计模式?
❓ 痛点:没有设计模式的代码有多痛苦?
java
// 地狱级 if-else(每次加新功能都要改核心)
public void processOrder(Order order) {
if ("NORMAL".equals(order.getType())) {
// 正常订单逻辑(50行)
} else if ("VIP.equals(order.getType())) {
// VIP 订单逻辑(60行)
} else if ("GROUP_BUY".equals(order.getType())) {
// 拼团逻辑(70行)
}
// 老板说要加"预售"?再加一个 else if...
}
后果:
-
🔥 改一处,崩三处(测试覆盖难)
-
🧩 无法复用(逻辑散落在各处)
-
👥 新人看不懂(协作成本高)
✅ 优化后代码(策略模式)
第1步:定义一个接口
java
public interface OrderHandler {
boolean supports(String type);
void handle(Order order);
}
第2步:每种订单写一个类
java
// 普通订单
public class NormalOrderHandler implements OrderHandler {
public boolean supports(String type) {
return "NORMAL".equals(type);
}
public void handle(Order order) {
System.out.println("处理普通订单");
}
}
// VIP 订单
public class VipOrderHandler implements OrderHandler {
public boolean supports(String type) {
return "VIP".equals(type);
}
public void handle(Order order) {
System.out.println("处理VIP订单");
}
}
// 拼团订单
public class GroupBuyHandler implements OrderHandler {
public boolean supports(String type) {
return "GROUP_BUY".equals(type);
}
public void handle(Order order) {
System.out.println("处理拼团订单");
}
}
第3步:主方法改成这样
java
// 把所有处理器放到一个列表里(实际项目中可用 Spring 自动注入)
List<OrderHandler> handlers = Arrays.asList(
new NormalOrderHandler(),
new VipOrderHandler(),
new GroupBuyHandler()
);
public void processOrder(Order order) {
for (OrderHandler handler : handlers) {
if (handler.supports(order.getType())) {
handler.handle(order);
return;
}
}
throw new IllegalArgumentException("不支持的订单类型: " + order.getType());
}
🎯 对比效果
| 场景 | 原始代码 | 优化后代码 |
|---|---|---|
| 加"预售订单" | 要改 processOrder 方法 |
只需新增一个 PresaleOrderHandler 类 |
| 代码结构 | 所有逻辑挤在一起 | 每种类型独立,清晰易读 |
| 测试 | 难以单独测某一种 | 每个 Handler 可单独测试 |
💡 本质:把"会变的"封装起来,让"不变的"稳定运行
二、SOLID 原则:隔离变化的 5 条军规
1. 单一职责(SRP)→ 一个类只干一件事
-
问题:UserService 既管用户信息,又发邮件、记日志
-
隔离变化:把"发邮件"、"记日志"拆出去
-
效果:改邮件逻辑不影响用户保存
2. 开闭原则(OCP)→ 对扩展开放,对修改关闭
-
问题:加新支付方式要改 OrderService
-
隔离变化:用策略模式,新增类不改旧代码
-
效果:需求变,代码不动
3. 里氏替换(LSP)→ 子类能无缝替换父类
-
问题:Square 继承 Rectangle,面积计算出错
-
隔离变化:正方形和矩形应为兄弟类,而非父子
-
效果:多态安全,不破坏原有逻辑
4. 接口隔离(ISP)→ 客户端只依赖需要的接口
-
问题:Printer 被迫实现 fax() 方法
-
隔离变化:拆成 Printer/Scanner/Fax 小接口
-
效果:类只实现自己需要的功能
5. 依赖倒置(DIP)→ 依赖抽象,不依赖具体
-
问题:OrderService 直接 new MySQLDatabase()
-
隔离变化:依赖 Database 接口,注入具体实现
-
效果:换 PostgreSQL?只需改配置!
三、23 种设计模式:如何隔离变化?
每个模式都回答一个问题:什么在变?怎么隔离?
🧱 创建型模式(5种):隔离"对象创建"的变化
| 模式 | 什么在变? | 怎么隔离? | Spring Boot 实战 |
|---|---|---|---|
| 单例 | 全局唯一实例 | 私有构造 + 静态方法 | @Component + @Scope("singleton") |
| 工厂方法 | 创建哪种对象 | 子类决定 | @Bean 方法返回不同实现 |
| 抽象工厂 | 创建产品族 | 工厂接口 | 多数据源配置(MySQLFactory / PGFactory) |
| 建造者 | 复杂对象构建步骤 | 分步构建 | RestTemplateBuilder, WebClient.builder() |
| 原型 | 对象初始化成本高 | 克隆现有对象 | @Scope("prototype") Bean |
✅ 核心:不让业务代码关心"对象怎么来"
🔗 结构型模式(7种):隔离"结构组合"的变化
| 模式 | 什么在变? | 怎么隔离? | Spring Boot 实战 |
|---|---|---|---|
| 适配器 | 接口不兼容 | 包装旧接口 | 集成第三方 SDK(如微信支付适配器) |
| 装饰器 | 功能动态增减 | 包装增强 | BufferedInputStream, Spring Security 过滤器链 |
| 代理 | 控制对象访问 | 中介拦截 | Spring AOP(事务、日志)、Feign Client |
| 外观 | 子系统复杂 | 提供统一入口 | @Service 封装多个 Repository 调用 |
| 桥接 | 抽象与实现耦合 | 分离维度 | 日志框架(Logger + Appender) |
| 组合 | 树形结构 | 统一处理 | 菜单权限树、组织架构树 |
| 享元 | 大量相似对象 | 共享内部状态 | 数据库连接池、线程池 |
✅ 核心:不让调用方知道"内部怎么组合"
🔄 行为型模式(11种):隔离"行为算法"的变化
| 模式 | 什么在变? | 怎么隔离? | Spring Boot 实战 |
|---|---|---|---|
| 策略 | 算法选择 | 封装算法 | 支付方式、折扣计算、路由规则 |
| 观察者 | 事件通知 | 松耦合监听 | ApplicationEventPublisher, Spring 事件机制 |
| 责任链 | 请求处理链 | 传递处理 | Spring Security Filter Chain、审批流 |
| 命令 | 请求封装 | 对象化请求 | 任务队列、撤销操作(如 Redis Queue) |
| 状态 | 状态行为 | 状态驱动 | 订单状态机(待支付 → 已支付 → 已发货) |
| 模板方法 | 算法骨架 | 固定流程 | JdbcTemplate, RestTemplate |
| 迭代器 | 遍历方式 | 统一访问 | List.iterator(), Stream API |
| 中介者 | 对象交互 | 中心协调 | 消息总线、事件中心 |
| 备忘录 | 状态保存 | 快照恢复 | 游戏存档、表单草稿 |
| 访问者 | 新操作 | 外部定义 | 报表生成、AST 遍历 |
| 解释器 | 语法规则 | 解析执行 | 规则引擎(如 Drools)、简单表达式 |
✅ 核心:不让主流程知道"具体怎么执行"
四、Spring Boot 中的最佳实践
a、创建型模式(5种)
1. 单例模式(Singleton)
隔离变化:全局唯一实例(如配置、工具类)
Spring 实现:默认所有 Bean 都是单例
java
@Service
public class RedisCacheService {
// 整个应用只有一个实例
public String get(String key) {
return redisTemplate.opsForValue().get(key);
}
}
✅ 效果:无需手动管理实例,Spring 自动保证单例。
2. 工厂方法模式(Factory Method)
隔离变化:对象创建逻辑
Spring 实现:
@Bean方法
java
// 1. 定义接口
public interface Payment {
String getType(); // 返回 "alipay" 或 "wechat"
void pay(Order order);
}
// 2. 实现类
@Component
public class Alipay implements Payment {
public String getType() { return "alipay"; }
public void pay(Order order) { ... }
}
@Component
public class WechatPay implements Payment {
public String getType() { return "wechat"; }
public void pay(Order order) { ... }
}
// 3. 策略工厂(自动注册)
@Service
public class PaymentFactory {
private final Map<String, Payment> payments;
public PaymentFactory(List<Payment> paymentList) {
this.payments = paymentList.stream()
.collect(Collectors.toMap(Payment::getType, p -> p));
}
public Payment get(String type) {
return payments.get(type);
}
}
// 4. 使用
@Service
public class OrderService {
@Autowired private PaymentFactory paymentFactory;
public void createOrder(Order order) {
Payment payment = paymentFactory.get(order.getPayType());
payment.pay(order);
}
}
✅ 效果:根据参数动态创建对象。
3. 抽象工厂模式(Abstract Factory)
隔离变化:产品族(如多环境数据源)
Spring 实现:Profile + 条件装配
java
@Configuration
@Profile("prod")
public class ProdDatabaseFactory {
@Bean public DataSource dataSource() { return new HikariDataSource(); }
@Bean public JdbcTemplate jdbcTemplate(DataSource ds) { return new JdbcTemplate(ds); }
}
@Configuration
@Profile("test")
public class TestDatabaseFactory {
@Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder().build(); }
@Bean public JdbcTemplate jdbcTemplate(DataSource ds) { return new JdbcTemplate(ds); }
}
✅ 效果:整套组件一键切换,无需改业务代码。
4. 建造者模式(Builder)
隔离变化:复杂对象构建步骤
Spring 实现:
WebClient.builder()
java
@Service
public class ApiService {
private final WebClient webClient;
public ApiService() {
this.webClient = WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader("User-Agent", "MyApp/1.0")
.build();
}
public Mono<String> getData(String path) {
return webClient.get().uri(path).retrieve().bodyToMono(String.class);
}
}
✅ 效果:构建过程清晰,参数可选,避免构造函数爆炸。
5. 原型模式(Prototype)
隔离变化:高成本对象初始化
Spring 实现:
@Scope("prototype")
java
@Component
@Scope("prototype")
public class OrderContext {
private String orderId;
private LocalDateTime createTime = LocalDateTime.now();
public void setOrderId(String id) { this.orderId = id; }
// ...
}
✅ 效果:每次注入都是新实例,避免状态污染(如请求级上下文)。
b、结构型模式(7种)
6. 适配器模式(Adapter)
隔离变化:第三方接口不兼容
Spring 实现:封装 SDK
java
// 第三方 SDK
class WxPaySDK {
void pay(String openid, double amount) { /* 微信支付 */ }
}
// 适配器
@Component
public class WxPayAdapter implements Payment {
private final WxPaySDK sdk = new WxPaySDK();
@Override
public void pay(Order order) {
sdk.pay(order.getUser().getOpenid(), order.getAmount());
}
}
✅ 效果:业务只依赖 Payment 接口,不关心微信细节。
7. 装饰器模式(Decorator)
隔离变化:功能动态增强
Spring 实现:AOP 或包装 Bean
java
@Component
@Primary // 优先注入
public class LoggingUserService implements UserService {
private final UserService target;
public LoggingUserService(@Qualifier("userServiceImpl") UserService target) {
this.target = target;
}
@Override
public User getUser(Long id) {
log.info("查询用户: {}", id);
return target.getUser(id); // 增强原功能
}
}
✅ 效果:日志、缓存、限流等功能可叠加,不侵入核心逻辑。
8. 代理模式(Proxy)
隔离变化:控制对象访问(事务、安全等)
Spring 实现:Spring AOP(自动代理)
java
@Service
public class OrderService {
@Transactional // Spring 自动生成代理,开启事务
public void createOrder(Order order) {
orderRepository.save(order);
inventoryService.deduct(order.getItems());
}
}
✅ 效果:事务、缓存、安全等横切关注点与业务完全解耦。
9. 外观模式(Facade)
隔离变化:子系统复杂性
Spring 实现:
@Service封装多个依赖
java
@Service
public class OrderFacade {
@Autowired private OrderRepository orderRepo;
@Autowired private InventoryService inventory;
@Autowired private NotificationService notify;
public void createOrder(OrderDTO dto) {
Order order = orderRepo.save(dto.toEntity());
inventory.deduct(order.getItems());
notify.send(order.getUser(), "下单成功");
}
}
✅ 效果:调用方只需面对一个简单接口,内部复杂性被隐藏。
10. 桥接模式(Bridge)
隔离变化:抽象与实现紧耦合
两个维度的变化:
抽象维度(如:消息类型:通知、告警、营销)
实现维度(如:发送渠道:邮件、短信、微信)
组合而非继承:抽象持有实现的引用
java
// 实现维度:发送渠道
public interface MessageSender {
void send(String msg);
}
@Component
public class EmailSender implements MessageSender {
public void send(String msg) { System.out.println("📧 邮件: " + msg); }
}
@Component
public class SmsSender implements MessageSender {
public void send(String msg) { System.out.println("📱 短信: " + msg); }
}
// 抽象维度:消息类型
public abstract class Message {
protected MessageSender sender; // 持有实现的引用(桥接!)
public Message(MessageSender sender) {
this.sender = sender;
}
public abstract void send(String content);
}
// 通知消息
public class NotificationMessage extends Message {
public NotificationMessage(MessageSender sender) {
super(sender);
}
@Override
public void send(String content) {
sender.send("[通知] " + content);
}
}
// 告警消息
public class AlertMessage extends Message {
public AlertMessage(MessageSender sender) {
super(sender);
}
@Override
public void send(String content) {
sender.send("[🚨 告警] " + content);
}
}
// 营销消息
public class MarketingMessage extends Message {
public MarketingMessage(MessageSender sender) {
super(sender);
}
@Override
public void send(String content) {
sender.send("[🎁 营销] " + content);
}
}
@Service
public class MessageService {
@Autowired
private EmailSender emailSender;
@Autowired
private SmsSender smsSender;
public void demo() {
// 通知 + 邮件
new NotificationMessage(emailSender).send("系统升级");
// 告警 + 短信
new AlertMessage(smsSender).send("CPU 使用率过高!");
// 营销 + 邮件
new MarketingMessage(emailSender).send("双11大促开始了!");
}
}
✅ 效果:发送方式和通知逻辑独立演进,互不影响。
11. 组合模式(Composite)
隔离变化:树形结构处理差异
Spring 实现:菜单/权限树
-
统一接口:单个(叶子)和组合(容器)都实现同一个接口
-
递归处理:组合对象调用自己内部每个子对象的相同方法
java
public interface MenuComponent {
void render(); // 所有菜单元素(单个 or 组)都要能渲染
}
@Component
public class MenuItem implements MenuComponent {
public void render() {
System.out.println("渲染菜单项"); // 就干这一件事
}
}
@Component
public class MenuGroup implements MenuComponent {
// 存放子菜单(可以是 MenuItem,也可以是 MenuGroup!)
private List<MenuComponent> children = new ArrayList<>();
public void addChild(MenuComponent child) {
children.add(child);
}
public void render() {
// 关键!遍历所有子元素,调用它们的 render()
children.forEach(child -> child.render());
}
}
public class Main {
public static void main(String[] args) {
// 创建根菜单组
MenuGroup root = new MenuGroup();
// 添加单个菜单项
root.addChild(new MenuItem()); // "首页"
root.addChild(new MenuItem()); // "关于我们"
// 创建子菜单组
MenuGroup userMenu = new MenuGroup();
userMenu.addChild(new MenuItem()); // "个人中心"
userMenu.addChild(new MenuItem()); // "退出登录"
// 把子菜单组加入根菜单
root.addChild(userMenu);
// 渲染整个菜单!
root.render();
}
}
✅ 效果:统一处理单个和组合对象,客户端无需区分。
12. 享元模式(Flyweight)
隔离变化:大量相似对象内存开销
享元模式 = 共享不变的部分 + 传递变化的部分
能有效解决 大量重复小对象导致的内存问题。
java
// 标签享元接口
public interface UserTagFlyweight {
/**
* 显示标签(外部状态:userId, position)
*/
void display(Long userId, String position);
}
// 具体标签实现(内部状态:type, color, icon)
@Component
@Scope("prototype") // 每次从工厂获取时由工厂控制,不是 Spring 管理单例
public class ConcreteUserTag implements UserTagFlyweight {
private final String type; // 内部状态:标签类型(VIP/NEW/...)
private final String color; // 内部状态:颜色
private final String icon; // 内部状态:图标
public ConcreteUserTag(String type, String color, String icon) {
this.type = type;
this.color = color;
this.icon = icon;
}
@Override
public void display(Long userId, String position) {
System.out.printf("[用户%d] 在 %s 显示标签: %s | 颜色=%s | 图标=%s%n",
userId, position, type, color, icon);
}
}
@Component
public class UserTagFactory {
// 享元池:缓存所有已创建的标签(内部状态作为 key)
private final Map<String, UserTagFlyweight> tagPool = new ConcurrentHashMap<>();
/**
* 获取标签(相同 type/color/icon 只创建一次)
*/
public UserTagFlyweight getTag(String type, String color, String icon) {
String key = type + "_" + color + "_" + icon;
return tagPool.computeIfAbsent(key, k -> new ConcreteUserTag(type, color, icon));
}
// 用于监控
public int getPoolSize() {
return tagPool.size();
}
}
@Service
public class UserService {
@Autowired
private UserTagFactory tagFactory;
public void renderUserTags(Long userId) {
// 模拟用户拥有的标签(实际可能来自数据库)
List<TagConfig> userTags = getUserTagsFromDB(userId);
for (TagConfig config : userTags) {
// 从享元池获取标签(相同配置复用同一个对象)
UserTagFlyweight tag = tagFactory.getTag(
config.getType(),
config.getColor(),
config.getIcon()
);
// 显示标签(传入外部状态)
tag.display(userId, config.getPosition());
}
}
// 模拟数据库查询
private List<TagConfig> getUserTagsFromDB(Long userId) {
return Arrays.asList(
new TagConfig("VIP", "gold", "⭐", "header"),
new TagConfig("NEW", "green", "🆕", "profile"),
new TagConfig("VIP", "gold", "⭐", "sidebar") // 和第一个相同!
);
}
// 内部 DTO
private static class TagConfig {
String type, color, icon, position;
TagConfig(String type, String color, String icon, String position) {
this.type = type; this.color = color; this.icon = icon; this.position = position;
}
// getter...
}
}
@RestController
public class TestController {
@Autowired
private UserService userService;
@Autowired
private UserTagFactory tagFactory;
@GetMapping("/test")
public String test() {
System.out.println("=== 渲染用户 1001 ===");
userService.renderUserTags(1001L);
System.out.println("=== 渲染用户 1002 ===");
userService.renderUserTags(1002L);
System.out.println("享元池大小: " + tagFactory.getPoolSize()); // 应该是 2(VIP 和 NEW)
return "OK";
}
}
✅ 效果:共享内部状态,大幅节省资源。
c、行为型模式(11种)
13. 策略模式(Strategy)
隔离变化:算法选择(支付、折扣等)
Spring 实现:Map 自动注册(最常用!)
java
public interface DiscountStrategy {
String getType();
BigDecimal apply(Order order);
}
@Component
public class VipDiscount implements DiscountStrategy {
public String getType() { return "VIP"; }
public BigDecimal apply(Order order) { return order.getAmount().multiply(BigDecimal.valueOf(0.9)); }
}
@Component
public class HolidayDiscount implements DiscountStrategy {
public String getType() { return "HOLIDAY"; }
public BigDecimal apply(Order order) { return order.getAmount().multiply(BigDecimal.valueOf(0.8)); }
}
@Service
public class DiscountService {
private final Map<String, DiscountStrategy> strategies;
public DiscountService(List<DiscountStrategy> list) {
this.strategies = list.stream()
.collect(Collectors.toMap(DiscountStrategy::getType, s -> s));
}
public BigDecimal calculate(String type, Order order) {
return strategies.get(type).apply(order);
}
}
✅ 效果:新增折扣类型?只需写一个新类!零修改核心代码。
14. 观察者模式(Observer)
隔离变化:事件通知耦合
Spring 实现:
ApplicationEventPublisher(最常用!)
java
// 事件
public class OrderCreatedEvent {
private final Order order;
public OrderCreatedEvent(Order order) { this.order = order; }
public Order getOrder() { return order; }
}
// 发布
@Service
public class OrderService {
@Autowired private ApplicationEventPublisher publisher;
public void createOrder(Order order) {
orderRepository.save(order);
publisher.publishEvent(new OrderCreatedEvent(order)); // 发布事件
}
}
// 监听
@Component
public class SmsListener {
@EventListener
public void handle(OrderCreatedEvent event) {
sendSms(event.getOrder().getUser(), "下单成功");
}
}
@Component
public class PointsListener {
@EventListener
public void handle(OrderCreatedEvent event) {
addPoints(event.getOrder().getUser());
}
}
✅ 效果:新增"发券"?加一个 Listener 即可!完全解耦。
15. 责任链模式(Chain of Responsibility)
隔离变化:请求处理流程
Spring 实现:Filter Chain / 手动链
java
@Component
public class AuthHandler {
private final AuthHandler next;
public AuthHandler(@Nullable AuthHandler next) {
this.next = next;
}
public boolean handle(Request req) {
if (!checkAuth(req)) return false;
return next == null || next.handle(req); // 传递
}
}
// 配置链
@Configuration
public class HandlerChainConfig {
@Bean
public AuthHandler authChain(RateLimitHandler rateLimit, LogHandler log) {
return new AuthHandler(new RateLimitHandler(log));
}
}
✅ 效果:动态增减处理环节,流程灵活可配。
16. 命令模式(Command)
隔离变化:请求封装(支持撤销/队列)
Spring 实现:任务队列
java
// 定义命令接口
public interface Command {
void execute();
void undo();
}
// 定义 Receiver(真正干活的)
@Service
public class OrderReceiver {
@Transactional
public void createOrder(OrderDTO dto) {
// 完整业务逻辑:校验、保存、发事件...
Order order = new Order(dto);
orderRepository.save(order);
}
@Transactional
public void cancelOrder(Long orderId) {
orderRepository.deleteById(orderId);
}
}
// 命令只保存指令参数(不是实体!)
@Component
@Scope("prototype") // 每次需要新实例
public class CreateOrderCommand implements Command {
private final OrderReceiver receiver;
private final OrderDTO orderData; // 只存必要参数
private Long createdOrderId; // 用于 undo
public CreateOrderCommand(OrderReceiver receiver, OrderDTO orderData) {
this.receiver = receiver;
this.orderData = orderData;
}
@Override
public void execute() {
// 执行并记录结果(用于 undo)
Order order = new Order(orderData);
orderRepository.save(order);
this.createdOrderId = order.getId(); // 保存 ID 用于撤销
}
@Override
public void undo() {
if (createdOrderId != null) {
receiver.cancelOrder(createdOrderId);
}
}
}
// 命令工厂(避免手动 new)
@Component
public class CommandFactory {
@Autowired private OrderReceiver orderReceiver;
public Command createOrderCommand(OrderDTO dto) {
return new CreateOrderCommand(orderReceiver, dto);
}
}
// Invoker(命令调度器)
@Service
public class CommandInvoker {
// 同步执行
public void execute(Command command) {
command.execute();
}
// 异步执行(存入队列)
public void submitAsync(OrderDTO dto) {
// 只存 DTO 到 Redis(可序列化!)
redisTemplate.opsForList().leftPush("order-commands", dto);
}
// 消费队列(在消费者服务中)
@Scheduled(fixedDelay = 1000)
public void processQueue() {
OrderDTO dto = redisTemplate.opsForList().rightPop("order-commands", OrderDTO.class);
if (dto != null) {
Command cmd = commandFactory.createOrderCommand(dto);
cmd.execute(); // 执行命令
}
}
}
@RestController
public class OrderController {
@Autowired private CommandFactory commandFactory;
@Autowired private CommandInvoker invoker;
@PostMapping("/orders")
public String createOrder(@RequestBody OrderDTO dto) {
// 方式1:同步执行 + 支持撤销
Command cmd = commandFactory.createOrderCommand(dto);
invoker.execute(cmd);
// 可保存 cmd 到 session,后续调用 cmd.undo() 撤销
return "OK";
}
@PostMapping("/orders/async")
public String createOrderAsync(@RequestBody OrderDTO dto) {
// 方式2:异步执行
invoker.submitAsync(dto);
return "Submitted";
}
}
✅ 效果:请求可存储、可撤销、可异步执行。
17. 状态模式(State)
隔离变化:状态行为差异
Spring 实现:订单状态机
java
public interface OrderState {
void pay(Order order);
void ship(Order order);
}
@Component
public class PaidState implements OrderState {
public void pay(Order order) { throw new IllegalStateException("已支付"); }
public void ship(Order order) { order.setState(new ShippedState()); }
}
@Service
public class OrderService {
public void ship(Long orderId) {
Order order = repo.findById(orderId);
order.getState().ship(order); // 状态驱动行为
}
}
✅ 效果:避免巨型 if-else,状态行为清晰隔离。
18. 模板方法模式(Template Method)
隔离变化:算法骨架 vs 具体步骤
Spring 实现:
JdbcTemplate(最经典!)
java
public abstract class DataProcessor {
public final void process() {
loadData(); // 固定
parseData(); // 固定
saveData(); // 钩子(子类实现)
}
protected abstract void saveData();
}
@Component
public class CsvProcessor extends DataProcessor {
protected void saveData() { /* 保存 CSV */ }
}
✅ 效果:复用流程,定制细节,符合开闭原则。
19. 迭代器模式(Iterator)
隔离变化:遍历方式
Spring 实现:Stream API / Repository
java
// 1. 用户组(聚合对象)
public class UserGroup {
private List<User> users = new ArrayList<>();
public void addUser(User user) {
users.add(user);
}
// 关键:提供 iterator() 方法
public Iterator<User> iterator() {
return users.iterator(); // 返回 JDK 内置的迭代器
}
}
// 2. 使用迭代器(客户端不关心内部结构)
@Service
public class UserService {
public void processAllUsers(UserGroup group) {
// 显式使用 Iterator
Iterator<User> it = group.iterator();
while (it.hasNext()) {
User user = it.next();
process(user);
}
}
}
✅ 效果:统一访问聚合对象,客户端无需知道内部结构。
20. 中介者模式(Mediator)
隔离变化:对象间复杂交互
Spring 实现:事件总线 / 服务协调
java
// 用户(Colleague)------ 它们本来想直接通信!
public class User {
private String name;
private ChatRoomMediator mediator; // 只依赖中介者
public User(String name, ChatRoomMediator mediator) {
this.name = name;
this.mediator = mediator;
}
// 发消息(不直接发给其他人!)
public void send(String msg) {
mediator.sendMessage(msg, this);
}
public void receive(String msg) {
System.out.println(name + " 收到: " + msg);
}
}
// 中介者(Mediator)------ 协调通信
public class ChatRoomMediator {
private List<User> users = new ArrayList<>();
public void addUser(User user) {
users.add(user);
}
// 关键:中介者决定谁收到消息
public void sendMessage(String msg, User sender) {
for (User user : users) {
if (user != sender) { // 不发给自己
user.receive(sender.getName() + ": " + msg);
}
}
}
}
ChatRoomMediator chat = new ChatRoomMediator();
User alice = new User("Alice", chat);
User bob = new User("Bob", chat);
chat.addUser(alice);
chat.addUser(bob);
alice.send("你好!");
// 输出: Bob 收到: Alice: 你好!
✅ 效果:对象不直接通信,降低耦合,便于测试。
21. 备忘录模式(Memento)
隔离变化:内部状态保存/恢复
Spring 实现:表单草稿
java
// 1. 要保存状态的对象(比如订单)
class Order {
String status = "草稿";
// 保存当前状态
public Memento save() {
return new Memento(status);
}
// 恢复到之前的状态
public void restore(Memento m) {
this.status = m.status;
}
}
// 2. 备忘录(快照)
class Memento {
String status;
Memento(String status) {
this.status = status;
}
}
// 3. 使用示例
public class Main {
public static void main(String[] args) {
Order order = new Order();
// 1. 保存当前状态(草稿)
Memento draft = order.save();
// 2. 修改状态
order.status = "已提交";
System.out.println("当前状态: " + order.status); // 已提交
// 3. 恢复到草稿
order.restore(draft);
System.out.println("恢复后: " + order.status); // 草稿
}
}
✅ 效果:支持回滚、草稿、快照,不破坏封装性。
22. 访问者模式(Visitor)
隔离变化:新操作 vs 对象结构
Spring 实现:报表生成
-
Element(元素):你的数据结构(比如订单、用户、商品)
-
Visitor(访问者):想对这些数据做不同操作的人(比如生成 PDF、发邮件、统计报表)
java
// 1.定义"数据"(Element)
// 所有能被访问的数据都要实现这个接口
public interface Element {
void accept(Visitor visitor); // 接受访问者
}
// 订单数据
public class Order implements Element {
private String id;
private double amount;
// 关键:把自己交给访问者
public void accept(Visitor visitor) {
visitor.visit(this); // 注意:this 是 Order 类型!
}
// getter...
public String getId() { return id; }
public double getAmount() { return amount; }
}
// 2.定义"操作"(Visitor)
// 所有操作都要实现这个接口
public interface Visitor {
void visit(Order order); // 专门处理 Order
// 如果还有 User,就加 void visit(User user);
}
// 操作1:生成 PDF 报表
@Component
public class PdfReportVisitor implements Visitor {
public void visit(Order order) {
System.out.println("生成 PDF 报表: 订单 " + order.getId());
// 实际:用 iText 生成 PDF
}
}
// 操作2:发送通知(新增!)
@Component
public class SmsVisitor implements Visitor {
public void visit(Order order) {
System.out.println("发短信通知: 订单金额 " + order.getAmount());
}
}
// 3. 使用方式
Order order = new Order("1001", 99.9);
// 想生成 PDF?
PdfReportVisitor pdfVisitor = new PdfReportVisitor();
order.accept(pdfVisitor); // 输出:生成 PDF 报表: 订单 1001
// 想发短信?
SmsVisitor smsVisitor = new SmsVisitor();
order.accept(smsVisitor); // 输出:发短信通知: 订单金额 99.9
✅ 效果:新增报表类型不改 Order 类,符合开闭原则。
23. 解释器模式(Interpreter)
隔离变化:语法规则解析
Spring 友好:用
@Component管理基础规则
java
// 1. 表达式接口(解释器核心)
public interface RuleExpression {
boolean interpret(User user);
}
// 2. 基础条件:年龄 > 18
@Component
public class AgeRule implements RuleExpression {
public boolean interpret(User user) {
return user.getAge() > 18;
}
}
// 3. 基础条件:是 VIP
@Component
public class VipRule implements RuleExpression {
public boolean interpret(User user) {
return user.isVip();
}
}
// 4. 组合规则:AND
@Component
public class AndRule implements RuleExpression {
private final RuleExpression left, right;
public AndRule(RuleExpression left, RuleExpression right) {
this.left = left;
this.right = right;
}
public boolean interpret(User user) {
return left.interpret(user) && right.interpret(user);
}
}
// 5. 使用(在 Service 中组合规则)
@Service
public class UserService {
@Autowired
private AgeRule ageRule;
@Autowired
private VipRule vipRule;
public boolean canAccessPremium(User user) {
// 手动组合:age > 18 AND vip == true
RuleExpression rule = new AndRule(ageRule, vipRule);
return rule.interpret(user);
}
}
✅ 效果:"组合对象 + interpret()" 就是解释器模式的核心思想。
五、总结:设计模式不是银弹,而是"隔离变化"的工具箱
📌 记住三句话:
-
"会变的"和"不变的"必须分开
-
支付方式会变 → 抽成策略
-
日志逻辑会变 → 用 AOP 代理
-
通知渠道会变 → 用观察者
-
-
SOLID 是隔离变化的操作手册
-
单一职责 → 别让一个类干太多
-
开闭原则 → 新需求别改老代码
-
依赖倒置 → 依赖接口,不依赖实现
-
-
Spring Boot 天然支持设计模式
-
@Component= 工厂 -
AOP = 代理
-
事件 = 观察者
-
@Bean= 策略注册
-
"好的代码,不是写出来的,而是'隔离'出来的。"