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 问题
- 单例双重检查锁为什么用 volatile? → 禁止指令重排,防半成品对象
- JDK 动态代理 vs CGLIB? → 接口 vs 继承;Spring Boot 2.x 默认 CGLIB
- 策略 vs 状态? → 外部选 vs 自动切;结构相同意图不同
- 观察者 vs 发布订阅? → 直接通知 vs 中间件解耦
- 装饰器 vs 代理? → 增强叠加 vs 控制访问
- 工厂三种区别? → switch → 每产品一工厂 → 每系列一工厂
- 模板方法 vs 策略? → 继承改步骤 vs 组合换算法
- 责任链实际应用? → Servlet Filter、Spring Interceptor、Netty
- 建造者解决什么? → 构造参数多、链式调用、build() 校验
- Spring AOP 底层原理? → 动态代理(JDK / CGLIB)
万能答题框架
- 一句话说明解决什么问题
- 一个生活类比
- 代码/框架中的应用场景
- 和相似模式的区别(加分)
- 结合项目实际经验(最加分)