设计模式的本质:隔离变化

32 阅读17分钟

 设计模式的本质:隔离变化

一、为什么要学设计模式?

❓ 痛点:没有设计模式的代码有多痛苦?

// 地狱级 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步:定义一个接口
public interface OrderHandler {
    boolean supports(String type);
    void handle(Order order);
}
第2步:每种订单写一个类
// 普通订单
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步:主方法改成这样
// 把所有处理器放到一个列表里(实际项目中可用 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)
建造者复杂对象构建步骤分步构建RestTemplateBuilderWebClient.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)
状态状态行为状态驱动订单状态机(待支付 → 已支付 → 已发货)
模板方法算法骨架固定流程JdbcTemplateRestTemplate
迭代器遍历方式统一访问List.iterator(), Stream API
中介者对象交互中心协调消息总线、事件中心
备忘录状态保存快照恢复游戏存档、表单草稿
访问者新操作外部定义报表生成、AST 遍历
解释器语法规则解析执行规则引擎(如 Drools)、简单表达式

✅ 核心:不让主流程知道“具体怎么执行”

四、Spring Boot 中的最佳实践

a、创建型模式(5种)

1. 单例模式(Singleton)

隔离变化:全局唯一实例(如配置、工具类)
Spring 实现:默认所有 Bean 都是单例

@Service
public class RedisCacheService {
    // 整个应用只有一个实例
    public String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }
}

✅ 效果:无需手动管理实例,Spring 自动保证单例。

2. 工厂方法模式(Factory Method)

隔离变化:对象创建逻辑
Spring 实现:@Bean 方法

// 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 + 条件装配

@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()

@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")

@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

// 第三方 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

@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(自动代理)

@Service
public class OrderService {

    @Transactional // Spring 自动生成代理,开启事务
    public void createOrder(Order order) {
        orderRepository.save(order);
        inventoryService.deduct(order.getItems());
    }
}

✅ 效果:事务、缓存、安全等横切关注点与业务完全解耦。

9. 外观模式(Facade)

隔离变化:子系统复杂性
Spring 实现:@Service 封装多个依赖

@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)

隔离变化:抽象与实现紧耦合
两个维度的变化:

抽象维度(如:消息类型:通知、告警、营销)

实现维度(如:发送渠道:邮件、短信、微信)

组合而非继承:抽象持有实现的引用

// 实现维度:发送渠道
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 实现:菜单/权限树

  • 统一接口:单个(叶子)和组合(容器)都实现同一个接口

  • 递归处理:组合对象调用自己内部每个子对象的相同方法

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)

隔离变化:大量相似对象内存开销
享元模式 = 共享不变的部分 + 传递变化的部分

能有效解决 大量重复小对象导致的内存问题。

// 标签享元接口
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 自动注册(最常用!)

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(最常用!)

// 事件
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 / 手动链

@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 实现:任务队列

// 定义命令接口
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 实现:订单状态机

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(最经典!)

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

// 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 实现:事件总线 / 服务协调

// 用户(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 实现:表单草稿

// 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、发邮件、统计报表)

// 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 管理基础规则

// 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()” 就是解释器模式的核心思想。

五、总结:设计模式不是银弹,而是“隔离变化”的工具箱

📌 记住三句话:

  1. “会变的”和“不变的”必须分开

    • 支付方式会变 → 抽成策略

    • 日志逻辑会变 → 用 AOP 代理

    • 通知渠道会变 → 用观察者

  2. SOLID 是隔离变化的操作手册

    • 单一职责 → 别让一个类干太多

    • 开闭原则 → 新需求别改老代码

    • 依赖倒置 → 依赖接口,不依赖实现

  3. Spring Boot 天然支持设计模式

    • @Component = 工厂

    • AOP = 代理

    • 事件 = 观察者

    • @Bean = 策略注册

“好的代码,不是写出来的,而是‘隔离’出来的。”