设计模式速查

Java 设计模式速查手册

12 个核心设计模式 · 一看就懂的 Java 代码 · 面试 & 开发双保险


目录

# 模式 类别 一句话理解
1 [单例模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 创建型 全局只有一个实例
2 [工厂模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 创建型 创建对象交给工厂
3 [建造者模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 创建型 链式调用构建复杂对象
4 [代理模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 结构型 中间加一层做增强
5 [装饰器模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 结构型 一层层叠加功能
6 [适配器模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 结构型 转换不兼容的接口
7 [外观模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 结构型 统一简单入口
8 [策略模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 行为型 多种做法自由切换
9 [观察者模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 行为型 状态变了自动通知
10 [模板方法模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 行为型 流程固定步骤可变
11 [责任链模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 行为型 请求沿链传递处理
12 [状态模式](# 模式 类别 一句话理解 1 单例模式 创建型 全局只有一个实例 2 工厂模式 创建型 创建对象交给工厂 3 建造者模式 创建型 链式调用构建复杂对象 4 代理模式 结构型 中间加一层做增强 5 装饰器模式 结构型 一层层叠加功能 6 适配器模式 结构型 转换不兼容的接口 7 外观模式 结构型 统一简单入口 8 策略模式 行为型 多种做法自由切换 9 观察者模式 行为型 状态变了自动通知 10 模板方法模式 行为型 流程固定步骤可变 11 责任链模式 行为型 请求沿链传递处理 12 状态模式 行为型 状态不同行为不同) 行为型 状态不同行为不同

速记总览

创建型(怎么创建对象)

  • 单例 → 只有一个实例
  • 工厂 → 不用自己 new
  • 建造者 → 参数太多用链式调用

结构型(怎么组合对象)

  • 代理 → 中间加一层(控制访问)
  • 装饰器 → 一层层叠加(增强功能)
  • 适配器 → 接口不兼容就转一下
  • 外观 → 太复杂就给一个简单入口

行为型(怎么协作)

  • 策略 → 多种做法切换
  • 观察者 → 事件通知
  • 模板方法 → 流程固定步骤可变
  • 责任链 → 层层传递
  • 状态 → 状态机

设计原则口诀:单一职责开闭口,依赖接口里替换(SOLID)+ 组合优于继承


1. 单例模式(Singleton)

保证一个类在整个程序中只有一个实例。

场景:数据库连接池、配置读取、日志对象

三个关键点:构造方法私有化 + 内部持有唯一实例 + 全局访问方法

⭐ 推荐写法:静态内部类

java 复制代码
public class Printer {

    private Printer() {
        System.out.println("打印机被创建了");
    }

    // 静态内部类:用到才加载(懒加载),JVM 类加载保证线程安全
    private static class Holder {
        static final Printer INSTANCE = new Printer();
    }

    public static Printer getInstance() {
        return Holder.INSTANCE;
    }

    public void print(String content) {
        System.out.println("打印:" + content);
    }
}
java 复制代码
Printer p1 = Printer.getInstance();
Printer p2 = Printer.getInstance();
System.out.println(p1 == p2); // true

面试写法:双重检查锁

java 复制代码
public class Printer {

    private static volatile Printer instance = null;  // volatile 禁止指令重排

    private Printer() {}

    public static Printer getInstance() {
        if (instance == null) {              // 第一次检查(不用抢锁)
            synchronized (Printer.class) {
                if (instance == null) {      // 第二次检查(防重复创建)
                    instance = new Printer();
                }
            }
        }
        return instance;
    }
}
写法 线程安全 懒加载 推荐度
饿汉式(直接 new) ✅ ❌ ⭐⭐⭐
懒汉式(if null) ❌ ✅ ❌
双重检查锁 ✅ ✅ ⭐⭐⭐⭐
静态内部类 ✅ ✅ ⭐⭐⭐⭐⭐

2. 工厂模式(Factory)

把创建对象交给工厂,使用者只管"要什么"。

场景:Spring BeanFactory、Calendar.getInstance()、JDBC Connection

简单工厂(最常用)

java 复制代码
// 产品接口
public interface Shape {
    void draw();
}

// 具体产品
public class Circle implements Shape {
    @Override
    public void draw() { System.out.println("画圆形 ⭕"); }
}

public class Rectangle implements Shape {
    @Override
    public void draw() { System.out.println("画矩形 ⬜"); }
}

// 简单工厂
public class ShapeFactory {
    public static Shape create(String type) {
        switch (type) {
            case "circle":    return new Circle();
            case "rectangle": return new Rectangle();
            default: throw new IllegalArgumentException("不支持的类型:" + type);
        }
    }
}
java 复制代码
Shape shape = ShapeFactory.create("circle");
shape.draw();  // 画圆形 ⭕

工厂方法(符合开闭原则)

java 复制代码
// 工厂接口
public interface Factory {
    Shape create();
}

// 每种产品对应一个工厂
public class CircleFactory implements Factory {
    @Override
    public Shape create() { return new Circle(); }
}

public class RectangleFactory implements Factory {
    @Override
    public Shape create() { return new Rectangle(); }
}
java 复制代码
Shape shape = new CircleFactory().create();
shape.draw();  // 画圆形 ⭕
// 新增产品?加一个新类,老代码不用改!
对比 简单工厂 工厂方法 抽象工厂
工厂数量 1 个 每产品 1 个 每系列 1 个
新增产品 改 switch ❌ 加新类 ✅ 加新类 ✅
使用频率 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐

3. 建造者模式(Builder)

链式调用一步步构建复杂对象,解决构造函数参数太多的问题。

场景:StringBuilder、OkHttpClient、Lombok @Builder

java 复制代码
public class User {

    private final String name;
    private final int age;
    private final String email;
    private final String phone;

    // 私有构造,只能通过 Builder 创建
    private User(UserBuilder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.email = builder.email;
        this.phone = builder.phone;
    }

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + ", email='" + email + "', phone='" + phone + "'}";
    }

    // ======== 内部静态 Builder ========
    public static class UserBuilder {

        private String name;
        private int age;
        private String email;
        private String phone;

        public UserBuilder name(String name)   { this.name = name;   return this; }
        public UserBuilder age(int age)        { this.age = age;     return this; }
        public UserBuilder email(String email) { this.email = email; return this; }
        public UserBuilder phone(String phone) { this.phone = phone; return this; }

        public User build() {
            if (name == null || name.isEmpty()) {
                throw new IllegalArgumentException("用户名不能为空!");
            }
            return new User(this);
        }
    }

    // 入口方法
    public static UserBuilder builder() {
        return new UserBuilder();
    }
}
java 复制代码
User user = User.builder()
        .name("张三")
        .age(25)
        .email("zhangsan@example.com")
        .build();

System.out.println(user);
// User{name='张三', age=25, email='zhangsan@example.com', phone='null'}

核心原理 :每个 setter 方法 return this,实现链式调用。

Lombok 简写:

java 复制代码
@Builder
public class User {
    private String name;
    private int age;
    private String email;
    private String phone;
}

4. 代理模式(Proxy)

不直接访问目标对象,通过代理间接访问,在中间做增强(日志/权限/事务)。

场景:Spring AOP、MyBatis Mapper、RPC 框架、懒加载

静态代理

java 复制代码
// 接口
public interface UserService {
    User findById(int id);
}

// 真实实现
public class UserServiceImpl implements UserService {
    @Override
    public User findById(int id) {
        System.out.println(" → 查数据库,ID:" + id);
        return new User(id, "张三");
    }
}

// 代理类
public class UserServiceProxy implements UserService {

    private UserService target;

    public UserServiceProxy(UserService target) {
        this.target = target;
    }

    @Override
    public User findById(int id) {
        System.out.println("【日志】开始查询");
        long start = System.currentTimeMillis();

        User user = target.findById(id);  // 调用真实对象

        long end = System.currentTimeMillis();
        System.out.println("【日志】查询完毕,耗时 " + (end - start) + "ms");
        return user;
    }
}
java 复制代码
UserService proxy = new UserServiceProxy(new UserServiceImpl());
proxy.findById(1);
// 【日志】开始查询
//   → 查数据库,ID:1
// 【日志】查询完毕,耗时 2ms

⭐ JDK 动态代理(一个 Handler 搞定所有接口)

java 复制代码
import java.lang.reflect.*;

public class LogHandler implements InvocationHandler {

    private Object target;

    public LogHandler(Object target) {
        this.target = target;
    }

    // 代理对象的任何方法调用,都经过这里
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("【日志】开始执行:" + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("【日志】执行完毕:" + method.getName());
        return result;
    }
}
java 复制代码
UserService proxy = (UserService) Proxy.newProxyInstance(
        realService.getClass().getClassLoader(),  // 类加载器
        realService.getClass().getInterfaces(),   // 目标接口
        new LogHandler(realService)               // 代理处理器
);
proxy.findById(1);

JDK 动态代理 vs CGLIB

对比项 JDK 动态代理 CGLIB
原理 实现接口 继承目标类
需要接口 ✅ 必须 ❌ 不需要
Java 版本 JDK 自带 需额外库
Spring 默认 有接口用它 没接口用它

5. 装饰器模式(Decorator)

不改原代码,通过一层层包装动态叠加功能。

场景:Java IO 流、Collections.synchronizedList()

和代理的区别:装饰器 = 增强功能(叠加),代理 = 控制访问(把关)

java 复制代码
// 组件接口
public interface Tea {
    String getDescription();
    double getPrice();
}

// 基础组件
public class MilkTea implements Tea {
    @Override
    public String getDescription() { return "原味奶茶"; }
    @Override
    public double getPrice() { return 10.0; }
}

// 装饰器基类(实现同一个接口 + 持有被装饰对象)
public abstract class TeaDecorator implements Tea {
    protected Tea tea;

    public TeaDecorator(Tea tea) { this.tea = tea; }
}

// 具体装饰器:珍珠
public class PearlDecorator extends TeaDecorator {
    public PearlDecorator(Tea tea) { super(tea); }

    @Override
    public String getDescription() { return tea.getDescription() + " + 珍珠"; }

    @Override
    public double getPrice() { return tea.getPrice() + 3.0; }
}

// 具体装饰器:椰果
public class CoconutDecorator extends TeaDecorator {
    public CoconutDecorator(Tea tea) { super(tea); }

    @Override
    public String getDescription() { return tea.getDescription() + " + 椰果"; }

    @Override
    public double getPrice() { return tea.getPrice() + 2.0; }
}

// 具体装饰器:布丁
public class PuddingDecorator extends TeaDecorator {
    public PuddingDecorator(Tea tea) { super(tea); }

    @Override
    public String getDescription() { return tea.getDescription() + " + 布丁"; }

    @Override
    public double getPrice() { return tea.getPrice() + 4.0; }
}
java 复制代码
// 像穿衣服一样一层层叠!
Tea tea = new MilkTea();                  // 原味奶茶 = 10.0
tea = new PearlDecorator(tea);            // + 珍珠   = 13.0
tea = new CoconutDecorator(tea);          // + 椰果   = 15.0
tea = new PuddingDecorator(tea);          // + 布丁   = 19.0

System.out.println(tea.getDescription()); // 原味奶茶 + 珍珠 + 椰果 + 布丁
System.out.println(tea.getPrice());       // 19.0

// 任意组合,不需要写新类!
Tea tea2 = new CoconutDecorator(new MilkTea());  // 原味奶茶 + 椰果 = 12.0

Java IO 就是装饰器:

java 复制代码
// 每一层包一个功能
BufferedReader reader = new BufferedReader(       // 装饰 2:加缓冲
    new InputStreamReader(                        // 装饰 1:字节转字符
        new FileInputStream("data.txt")           // 基础:读文件
    )
);

6. 适配器模式(Adapter)

把不兼容的接口"翻译"成你需要的接口。

场景:InputStreamReader、Arrays.asList()、第三方 SDK 接入

和外观的区别:适配器 = 转换接口,外观 = 简化接口

java 复制代码
// 你的系统接口
public interface Payment {
    void pay(double amount);
}

// 第三方 PayPal SDK(无法修改!)
public class PayPalSDK {
    public void makePayment(String currency, double value) {
        System.out.println("PayPal 支付:" + currency + " " + value);
    }
}

// 适配器:把 PayPal 翻译成 Payment
public class PayPalAdapter implements Payment {

    private PayPalSDK payPal;

    public PayPalAdapter(PayPalSDK payPal) {
        this.payPal = payPal;
    }

    @Override
    public void pay(double amount) {
        // 翻译工作:pay(amount) → makePayment("USD", amount)
        payPal.makePayment("USD", amount);
    }
}
java 复制代码
Payment payment = new PayPalAdapter(new PayPalSDK());
payment.pay(100);  // PayPal 支付:USD 100.0
// 调用者完全感觉不到 PayPal 的存在,统一用 pay(amount)!

两种形式:对象适配器(组合,推荐)vs 类适配器(继承)


7. 外观模式(Facade)

给一堆复杂子系统提供一个统一的简单入口。

场景:SLF4J、Spring ApplicationContext、万能遥控器

java 复制代码
// 子系统 1
public class Projector {
    public void turnOn()  { System.out.println("📽️ 投影仪已开启"); }
    public void turnOff() { System.out.println("📽️ 投影仪已关闭"); }
}

// 子系统 2
public class SoundSystem {
    public void turnOn()    { System.out.println("🔊 音响已开启"); }
    public void setVolume(int v) { System.out.println("🔊 音量:" + v); }
    public void turnOff()   { System.out.println("🔊 音响已关闭"); }
}

// 子系统 3
public class BluRayPlayer {
    public void turnOn()       { System.out.println("💿 播放器已开启"); }
    public void play(String movie) { System.out.println("💿 播放:" + movie); }
    public void turnOff()      { System.out.println("💿 播放器已关闭"); }
}

// ===== 外观类:统一入口 =====
public class HomeTheaterFacade {

    private Projector projector = new Projector();
    private SoundSystem sound = new SoundSystem();
    private BluRayPlayer player = new BluRayPlayer();

    // 一键看电影!
    public void watchMovie(String movie) {
        projector.turnOn();
        sound.turnOn();
        sound.setVolume(60);
        player.turnOn();
        player.play(movie);
        System.out.println("🎬 开始享受!");
    }

    // 一键关闭!
    public void endMovie() {
        player.turnOff();
        sound.turnOff();
        projector.turnOff();
        System.out.println("🎬 全部关闭!");
    }
}
java 复制代码
HomeTheaterFacade theater = new HomeTheaterFacade();
theater.watchMovie("复仇者联盟");   // 一行搞定所有操作
theater.endMovie();

8. 策略模式(Strategy)

把每种算法/做法封装成独立类,运行时自由切换,消灭 if-else。

场景:Comparator 排序、支付方式选择、折扣计算

和状态模式的区别:策略 = 外部主动选择,状态 = 内部自动切换

java 复制代码
// 策略接口
public interface DiscountStrategy {
    double calculate(double price);
}

// 具体策略 1:普通用户不打折
public class NormalDiscount implements DiscountStrategy {
    @Override
    public double calculate(double price) { return price; }
}

// 具体策略 2:VIP 八折
public class VipDiscount implements DiscountStrategy {
    @Override
    public double calculate(double price) { return price * 0.8; }
}

// 具体策略 3:新用户减 20
public class NewUserDiscount implements DiscountStrategy {
    @Override
    public double calculate(double price) { return Math.max(price - 20, 0); }
}

// 上下文:持有策略并使用
public class PriceContext {

    private DiscountStrategy strategy;

    public PriceContext(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public double calculatePrice(double price) {
        return strategy.calculate(price);
    }
}
java 复制代码
PriceContext context = new PriceContext(new NormalDiscount());
System.out.println(context.calculatePrice(100));  // 100.0

context.setStrategy(new VipDiscount());
System.out.println(context.calculatePrice(100));  // 80.0

context.setStrategy(new NewUserDiscount());
System.out.println(context.calculatePrice(100));  // 80.0(100-20)

组合技(策略 + 工厂):

java 复制代码
public class StrategyFactory {
    public static DiscountStrategy getStrategy(String userType) {
        switch (userType) {
            case "vip":  return new VipDiscount();
            case "new":  return new NewUserDiscount();
            default:     return new NormalDiscount();
        }
    }
}

// 一行搞定
PriceContext ctx = new PriceContext(StrategyFactory.getStrategy("vip"));
ctx.calculatePrice(100); // 80.0

9. 观察者模式(Observer)

当一个对象状态变化时,所有依赖它的对象自动收到通知。

场景:Spring Event、MQ 消息队列、Vue 响应式、GUI 事件

又叫:发布-订阅模式、事件驱动

java 复制代码
import java.util.*;

// 观察者接口
public interface WeatherObserver {
    void onTemperatureChanged(double temperature);
}

// 被观察者(发布者)
public class WeatherStation {

    private double temperature;
    private List<WeatherObserver> observers = new ArrayList<>();

    // 关注(注册)
    public void addObserver(WeatherObserver observer) {
        observers.add(observer);
    }

    // 取关(移除)
    public void removeObserver(WeatherObserver observer) {
        observers.remove(observer);
    }

    // 状态变化 → 自动通知所有观察者
    public void setTemperature(double temperature) {
        this.temperature = temperature;
        System.out.println("📡 温度更新为 " + temperature + "°C");
        for (WeatherObserver observer : observers) {
            observer.onTemperatureChanged(temperature);
        }
    }
}

// 具体观察者 1:手机
public class PhoneDisplay implements WeatherObserver {
    @Override
    public void onTemperatureChanged(double temperature) {
        System.out.println("📱 手机:温度 " + temperature + "°C");
    }
}

// 具体观察者 2:智能窗帘
public class SmartWindow implements WeatherObserver {
    @Override
    public void onTemperatureChanged(double temperature) {
        if (temperature > 35) {
            System.out.println("🪟 窗帘:温度过高,自动关闭防晒");
        } else {
            System.out.println("🪟 窗帘:温度适宜,保持打开");
        }
    }
}
java 复制代码
WeatherStation station = new WeatherStation();
station.addObserver(new PhoneDisplay());
station.addObserver(new SmartWindow());

station.setTemperature(30);
// 📡 温度更新为 30.0°C
// 📱 手机:温度 30.0°C
// 🪟 窗帘:温度适宜,保持打开

station.setTemperature(38);
// 📡 温度更新为 38.0°C
// 📱 手机:温度 38.0°C
// 🪟 窗帘:温度过高,自动关闭防晒

Spring Event 实战

java 复制代码
// 1. 定义事件
public class OrderCreatedEvent {
    private String orderId;

    public OrderCreatedEvent(String orderId) { this.orderId = orderId; }
    public String getOrderId() { return orderId; }
}

// 2. 发布事件
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void createOrder(String id) {
        publisher.publishEvent(new OrderCreatedEvent(id));
    }
}

// 3. 监听事件(多个观察者互不影响)
@Component
public class SmsListener {
    @EventListener
    public void onOrderCreated(OrderCreatedEvent e) {
        System.out.println("📱 发短信:" + e.getOrderId());
    }
}

@Component
public class WarehouseListener {
    @EventListener
    public void onOrderCreated(OrderCreatedEvent e) {
        System.out.println("📦 通知仓库:" + e.getOrderId());
    }
}

10. 模板方法模式(Template Method)

父类定义流程骨架(不可改),子类实现可变步骤。

场景:JdbcTemplate、HttpServlet、JUnit 测试框架

和策略模式的区别:模板 = 继承改步骤,策略 = 组合换算法

java 复制代码
// 抽象模板类
public abstract class DataExporter {

    // 模板方法:流程定死(final),子类不能改
    public final void export() {
        connectDatabase();    // 固定步骤
        queryData();          // 固定步骤
        convertData();        // 可变步骤!子类实现
        writeFile();          // 固定步骤
        closeConnection();    // 固定步骤
    }

    private void connectDatabase() { System.out.println("① 连接数据库"); }
    private void queryData()       { System.out.println("② 查询数据"); }
    private void writeFile()       { System.out.println("④ 写入文件"); }
    private void closeConnection() { System.out.println("⑤ 关闭连接"); }

    // 抽象步骤:子类必须实现
    protected abstract void convertData();
}

// 子类 1:CSV
public class CsvExporter extends DataExporter {
    @Override
    protected void convertData() {
        System.out.println("③ 转为 CSV 格式");
    }
}

// 子类 2:Excel
public class ExcelExporter extends DataExporter {
    @Override
    protected void convertData() {
        System.out.println("③ 转为 Excel 格式");
    }
}

// 子类 3:PDF
public class PdfExporter extends DataExporter {
    @Override
    protected void convertData() {
        System.out.println("③ 转为 PDF 格式");
    }
}
java 复制代码
new CsvExporter().export();
// ① 连接数据库
// ② 查询数据
// ③ 转为 CSV 格式    ← 只有这步不同!
// ④ 写入文件
// ⑤ 关闭连接

new PdfExporter().export();
// ① 连接数据库
// ② 查询数据
// ③ 转为 PDF 格式 ← 只有这步不同!
// ④ 写入文件
// ⑤ 关闭连接

钩子方法(可选覆盖)

java 复制代码
public abstract class DataExporter {

    public final void export() {
        // ...
        if (needAuditLog()) {  // 钩子方法:子类可覆盖
            System.out.println("★ 记录审计日志");
        }
        // ...
    }

    // 默认值,子类可以覆盖也可以不管
    protected boolean needAuditLog() {
        return true;
    }
}

11. 责任链模式(Chain of Responsibility)

把处理者串成链,请求沿链传递,直到有人处理。

场景:Servlet Filter、Spring Interceptor、Netty Pipeline、审批流程

两种类型:纯链(一人处理)vs 非纯链(每人都参与)

java 复制代码
// 处理者抽象类
public abstract class Approver {

    protected String name;
    protected Approver next;  // 下一个处理者

    public Approver(String name) { this.name = name; }

    // 设置下一个,返回 next 便于链式调用
    public Approver setNext(Approver next) {
        this.next = next;
        return next;
    }

    public abstract void approve(int days, String reason);
}

// 组长:≤ 1 天
public class TeamLeader extends Approver {
    public TeamLeader(String name) { super(name); }

    @Override
    public void approve(int days, String reason) {
        if (days <= 1) {
            System.out.println("【组长】" + name + " 审批通过:" + reason);
        } else {
            System.out.println("【组长】" + name + " 无权处理,转上级......");
            next.approve(days, reason);  // 传给下一个!
        }
    }
}

// 主管:≤ 3 天
public class Manager extends Approver {
    public Manager(String name) { super(name); }

    @Override
    public void approve(int days, String reason) {
        if (days <= 3) {
            System.out.println("【主管】" + name + " 审批通过:" + reason);
        } else {
            System.out.println("【主管】" + name + " 无权处理,转上级......");
            next.approve(days, reason);
        }
    }
}

// 总裁:全部放行
public class CEO extends Approver {
    public CEO(String name) { super(name); }

    @Override
    public void approve(int days, String reason) {
        System.out.println("【总裁】" + name + " 审批通过:" + reason);
    }
}
java 复制代码
// 组装责任链
Approver leader = new TeamLeader("小王");
Approver manager = new Manager("老李");
Approver ceo = new CEO("马老板");

leader.setNext(manager)   // 小王 → 老李
      .setNext(ceo);      // 老李 → 马老板

leader.approve(1, "感冒");
// 【组长】小王 审批通过:感冒

leader.approve(3, "家里有事");
// 【组长】小王 无权处理,转上级......
// 【主管】老李 审批通过:家里有事

leader.approve(15, "蜜月");
// 【组长】小王 无权处理,转上级......
// 【主管】老李 无权处理,转上级......
// 【总裁】马老板 审批通过:蜜月

12. 状态模式(State)

把每种状态封装成独立类,状态自己知道"能做什么"和"下一个状态"。

场景:订单状态机、审批流程、交通灯

和策略模式的区别:策略 = 外部主动选择,状态 = 内部自动切换(结构相同,意图不同)

java 复制代码
// 状态接口
public interface OrderState {
    void pay(Order order);
    void ship(Order order);
    void complete(Order order);
    void cancel(Order order);
}

// 上下文(订单)
public class Order {

    private String orderId;
    private OrderState currentState;

    public Order(String orderId) {
        this.orderId = orderId;
        this.currentState = new PendingState();  // 初始状态
        System.out.println("📋 订单 " + orderId + " 创建 → 待支付");
    }

    public void setState(OrderState state) { this.currentState = state; }

    // 委托给当前状态
    public void pay()      { currentState.pay(this); }
    public void ship()     { currentState.ship(this); }
    public void complete() { currentState.complete(this); }
    public void cancel()   { currentState.cancel(this); }
}
java 复制代码
// 状态 1:待支付
public class PendingState implements OrderState {
    @Override
    public void pay(Order order) {
        System.out.println("✅ 支付成功 → 已支付");
        order.setState(new PaidState());    // 自动切换状态!
    }

    @Override
    public void ship(Order order)     { System.out.println("❌ 未支付,不能发货"); }

    @Override
    public void complete(Order order) { System.out.println("❌ 未支付,不能完成"); }

    @Override
    public void cancel(Order order) {
        System.out.println("✅ 已取消");
        order.setState(new CancelledState());
    }
}

// 状态 2:已支付
public class PaidState implements OrderState {
    @Override
    public void pay(Order order) { System.out.println("⚠️ 已支付过"); }

    @Override
    public void ship(Order order) {
        System.out.println("✅ 发货成功 → 已发货");
        order.setState(new ShippedState());
    }

    @Override
    public void complete(Order order) { System.out.println("❌ 未发货"); }

    @Override
    public void cancel(Order order) {
        System.out.println("✅ 已取消(退款中)");
        order.setState(new CancelledState());
    }
}

// 状态 3:已发货
public class ShippedState implements OrderState {
    @Override
    public void pay(Order order)  { System.out.println("⚠️ 已支付过"); }

    @Override
    public void ship(Order order) { System.out.println("⚠️ 已发货过"); }

    @Override
    public void complete(Order order) {
        System.out.println("✅ 订单完成");
        order.setState(new CompletedState());
    }

    @Override
    public void cancel(Order order) { System.out.println("❌ 已发货不能取消"); }
}

// 状态 4:已完成
public class CompletedState implements OrderState {
    @Override
    public void pay(Order order)      { System.out.println("⚠️ 已完成"); }

    @Override
    public void ship(Order order)     { System.out.println("⚠️ 已完成"); }

    @Override
    public void complete(Order order) { System.out.println("⚠️ 已完成"); }

    @Override
    public void cancel(Order order)   { System.out.println("❌ 不能取消"); }
}

// 状态 5:已取消
public class CancelledState implements OrderState {
    @Override
    public void pay(Order order)      { System.out.println("❌ 已取消"); }

    @Override
    public void ship(Order order)     { System.out.println("❌ 已取消"); }

    @Override
    public void complete(Order order) { System.out.println("❌ 已取消"); }

    @Override
    public void cancel(Order order)   { System.out.println("⚠️ 已取消过"); }
}
java 复制代码
Order order = new Order("ORD-001");  // 📋 订单 ORD-001 创建 → 待支付

order.ship();      // ❌ 未支付,不能发货
order.pay();       // ✅ 支付成功 → 已支付
order.ship();      // ✅ 发货成功 → 已发货
order.cancel();    // ❌ 已发货不能取消
order.complete();  // ✅ 订单完成

状态流转图:

text 复制代码
待支付 ──pay()──▶ 已支付 ──ship()──▶ 已发货 ──complete()──▶ 已完成
   │                  │
   │cancel()          │cancel()
   ▼                  ▼
                  已取消

面试高频对比速查

相似模式区分

对比 区别关键词
代理 vs 装饰器 代理 = 控制访问;装饰器 = 增强叠加
策略 vs 状态 策略 = 外部选择;状态 = 内部自动切换
策略 vs 模板方法 策略 = 组合换算法;模板 = 继承改步骤
外观 vs 适配器 外观 = 简化接口;适配器 = 转换接口
工厂 vs 建造者 工厂 = 创建哪种对象;建造者 = 怎么一步步构建
观察者 vs 发布订阅 观察者 = 直接通知;发布订阅 = 通过中间件解耦
简单工厂 vs 工厂方法 简单 = 1 个工厂 + switch;工厂方法 = 每个产品 1 个工厂

SOLID 原则

原则 含义 相关模式
S 单一职责 一个类只干一件事 ---
O 开闭原则 对扩展开放,对修改关闭 策略、工厂方法、观察者
L 里氏替换 子类可替换父类 模板方法
I 接口隔离 接口要小而专 适配器
D 依赖倒置 依赖抽象不依赖具体 工厂、策略、观察者

口诀:单一职责开闭口,依赖接口里替换

面试 TOP 10 问题

  1. 单例双重检查锁为什么用 volatile? → 禁止指令重排,防半成品对象
  2. JDK 动态代理 vs CGLIB? → 接口 vs 继承;Spring Boot 2.x 默认 CGLIB
  3. 策略 vs 状态? → 外部选 vs 自动切;结构相同意图不同
  4. 观察者 vs 发布订阅? → 直接通知 vs 中间件解耦
  5. 装饰器 vs 代理? → 增强叠加 vs 控制访问
  6. 工厂三种区别? → switch → 每产品一工厂 → 每系列一工厂
  7. 模板方法 vs 策略? → 继承改步骤 vs 组合换算法
  8. 责任链实际应用? → Servlet Filter、Spring Interceptor、Netty
  9. 建造者解决什么? → 构造参数多、链式调用、build() 校验
  10. Spring AOP 底层原理? → 动态代理(JDK / CGLIB)

万能答题框架

  1. 一句话说明解决什么问题
  2. 一个生活类比
  3. 代码/框架中的应用场景
  4. 和相似模式的区别(加分)
  5. 结合项目实际经验(最加分)
相关推荐
Thomas.Sir35 分钟前
第15课:SpringBoot连接池详解:HikariCP配置、调优、监控,4.x连接池新特性
java·spring boot
deepseek231 小时前
Python日志拖慢请求?QueueHandler排队、丢失与退出实测
python·性能优化·logging·后端开发·queuehandler
用户91294046848421 小时前
Codex 从零到能交付(05):第一次改代码:生成一个文件清单脚本
python
Dmz丶1 小时前
前端转 AI 100 天 Day 38:Token 管理与成本优化——别让 API 账单爆炸
python
一条Go1 小时前
四个进程,一把锁:Alioth 的告警评测为什么不需要消息队列
后端·设计模式·架构
VimorphTech1 小时前
每批开 4 个线程,为什么限制不住 TTS 的总并发?
java·spring boot·spring
Pniubi1 小时前
Java为什么要分堆和栈
java·开发语言
杨凯凡1 小时前
Spring Boot 缓存一致性怎么保证?@Cacheable、@CacheEvict 与事务提交时机实战
java·spring boot·spring cache·后端开发·缓存一致性
用户298698530142 小时前
Python 自动化处理 Word 页眉页脚的几种典型场景
后端·python·api