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

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

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

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

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

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

📌 记住三句话:

  1. "会变的"和"不变的"必须分开

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

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

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

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

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

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

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

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

    • @Component = 工厂

    • AOP = 代理

    • 事件 = 观察者

    • @Bean = 策略注册

"好的代码,不是写出来的,而是'隔离'出来的。"

相关推荐
guchen662 小时前
令牌环式同步扩展
后端
v***57002 小时前
SpringBoot项目集成ONLYOFFICE
java·spring boot·后端
阿萨德528号2 小时前
Spring Boot实战:从零构建企业级用户中心系统(八)- 总结与最佳实践
java·spring boot·后端
Java小卷3 小时前
KIE Drools 10.x 规则引擎快速入门
java·后端
Java天梯之路4 小时前
Spring Boot 钩子全集实战(九):`@PostConstruct` 详解
java·spring boot·后端
十间fish4 小时前
车载大端序和tcp大端序
后端
毕设源码-郭学长4 小时前
【开题答辩全过程】以 基于Springboot图书管理系统为例,包含答辩的问题和答案
java·spring boot·后端
毕设源码-钟学长4 小时前
【开题答辩全过程】以 基于springboot网络游戏账号租赁以及出售系统为例,包含答辩的问题和答案
java·spring boot·后端