Administrator 10 阅读 面试

设计模式面试手册

面向后端 / Java 面试(原则与结构同样适用于 Go、Kotlin、TypeScript)。目标不是背定义,而是:一句话说清问题、讲清取舍、能落到代码和项目。


0. 面试官真正在听什么

问「你了解设计模式吗」通常不是考百科,而是三件事:

  1. 你能不能把复杂设计讲简单(抽象能力)
  2. 你知不知道什么时候不该用(工程判断)
  3. 你有没有在真实系统里做过权衡(项目可信度)

推荐答题结构(STAR 的设计版):

当时遇到 什么变化会频繁发生 → 如果硬写会 怎样爆炸 → 用 哪个模式 把变化点隔离 → 代价 是什么 → 线上/代码里 具体在哪

一句话原则:

模式解决的是「变化点」:把变的和不变的分开。


1. 先过设计原则(比 23 种更常被追问)

SOLID

原则 一句话 面试怎么说 反例
S 单一职责 一个类只有一个引起它变化的原因 Service 不要既算价格又发短信 UserService 里写 Excel 导出、发邮件、扣库存
O 开闭 对扩展开放,对修改关闭 加新策略不改老代码 每加一种支付就改 if-else 巨石
L 里氏替换 子类必须能替换父类 不要削弱父类契约 Square extends Rectangle 改了 setWidth 语义
I 接口隔离 不要强迫依赖用不到的方法 拆小接口 Animal 上既有 fly() 又有 swim()
D 依赖倒置 依赖抽象,不依赖具体 高层不 new 底层 OrderService 直接 new MysqlOrderRepo()

常一起考的

  • DRY:重复的是知识/规则,不是两行长得像的代码。乱抽公共方法比重复更糟。
  • KISS / YAGNI:没变化就不要上模式。面试里主动说「这里用策略是过度设计」会加分。
  • 迪米特(最少知识):只和直接朋友说话,避免 a.getB().getC().foo()。
  • 组合优于继承:继承是编译期耦合;装饰、策略、桥接都是组合。
  • 高内聚低耦合:模式的目的几乎都是降耦合。

高频追问:「开闭原则和策略模式什么关系?」
答:策略把变化封装成可替换对象,新增策略不必改上下文,是开闭的典型落地。


2. 23 种总览(先建立地图)

按 变化点 记,比按名字记牢。

创建型(怎么 new,别把 new 散落得到处都是)

模式 隔离的变化 一句话
单例 Singleton 实例个数 全局唯一访问点
工厂方法 Factory Method 产品类 子类决定创建哪个
抽象工厂 Abstract Factory 产品族 一次创建一套互相匹配的产品
建造者 Builder 构造步骤 / 可选参数 分步组装复杂对象
原型 Prototype 创建成本 克隆已有对象

结构型(怎么把类/对象拼起来)

模式 隔离的变化 一句话
适配器 Adapter 接口不匹配 把已有接口转成客户要的
桥接 Bridge 抽象与实现两维变化 两个维度独立扩展
组合 Composite 树形部分-整体 叶子和容器统一对待
装饰器 Decorator 职责叠加 运行时套功能
外观 Facade 子系统复杂度 提供一把 simplification 门面
享元 Flyweight 大量细粒度对象内存 共享不变状态
代理 Proxy 访问方式 控制/增强真实对象的访问

行为型(对象之间怎么协作、怎么分配职责)

模式 隔离的变化 一句话
职责链 Chain of Responsibility 谁处理 请求沿着链找处理者
命令 Command 请求本身 把请求封装成对象
解释器 Interpreter 文法 用类表示语法规则(面试少写,能辨认即可)
迭代器 Iterator 遍历方式 统一访问聚合,不暴露内部
中介者 Mediator 网状依赖 同事只和中介通信
备忘录 Memento 状态快照 不破坏封装地存档/回滚
观察者 Observer 通知名单 一改多知
状态 State 对象状态 状态对象化,行为随状态变
策略 Strategy 算法/规则 可互换的算法族
模板方法 Template Method 算法骨架中的某几步 父类定骨架,子类填步骤
访问者 Visitor 作用于稳定结构上的新操作 双分派,给对象结构加操作

面试加分句:
「创建型管对象从哪来,结构型管对象怎么包,行为型管对象怎么说话。」


3. 创建型详解

3.1 单例 Singleton

问题: 配置中心、线程池、ID 生成器这类东西,进程内只该有一份。

要点(Java 面试几乎必追线程安全):

// 1) 饿汉:类加载时创建,简单线程安全,可能浪费
public enum ConfigHolder { INSTANCE; } // 推荐:防反序列化、反射

// 2) 双重检查 + volatile(面试常写)
public class LazyHolder {
    private static volatile LazyHolder inst;
    public static LazyHolder get() {
        if (inst == null) {
            synchronized (LazyHolder.class) {
                if (inst == null) inst = new LazyHolder();
            }
        }
        return inst;
    }
}

// 3) 静态内部类(懒加载 + 类加载线程安全)
public class Holder {
    private static class H { static final Holder I = new Holder(); }
    public static Holder get() { return H.I; }
}

为什么 volatile: 防止指令重排,别的线程看到「半初始化」对象。

代价 / 别滥用:

  • 全局状态,测试难 mock
  • 隐藏依赖,变成「超级缓存」
  • 集群下 JVM 单例 ≠ 全局唯一(分布式要用 Redis / DB 约束)

真实例子: Spring 默认 Bean 是单例(容器管生命周期,比自己写单例更合适);Runtime.getRuntime();日志框架的 LoggerFactory。

追问: Spring 单例是线程安全的吗?
答:Bean 是单例,但 Bean 里的字段 不是。无状态 Service 可以单例;有可变成员要自己同步或改成 prototype / ThreadLocal。


3.2 简单工厂(非 GoF,但必考)

Payment p = PaymentFactory.create(type); // switch(type)

静态方法集中创建。违反开闭(每加类型改工厂)。小型、类型稳定时可用。引出工厂方法和策略。


3.3 工厂方法 Factory Method

问题: 创建哪个产品会变,但使用产品的流程不变。

结构: Creator.createProduct() 由子类实现;客户只依赖产品接口。

interface Product { void use(); }
abstract class Creator {
    abstract Product create();
    void doWork() { create().use(); } // 稳定流程
}

和简单工厂差在哪: 简单工厂一个类里 switch;工厂方法把「选哪个」下放到子类,符合开闭。

例子: Calendar.getInstance();日志 LoggerFactory.getLogger;Spring FactoryBean;集合 iterator() 也是工厂方法味道。


3.4 抽象工厂 Abstract Factory

问题: 要创建的是 一套配套产品(产品族),不能混搭。

例:WindowsFactory 产出 WindowsButton + WindowsScroll;MacFactory 产出 Mac 一套。客户拿 AbstractFactory,从不会 Windows 按钮配 Mac 滚动条。

和工厂方法: 工厂方法是「一个产品」的升级;抽象工厂是「多个相关产品」的工厂方法集合。

例子: JDBC 的 Connection 能产出配套的 Statement / ResultSet(同一厂商驱动);UI 主题;跨云 SDK 的一组客户端。

追问: 新加一种产品(产品等级)怎么办?
答:抽象工厂所有工厂都要加方法,产品等级扩展难、产品族扩展易。反过来工厂方法更好扩展单一产品类型。


3.5 建造者 Builder

问题: 对象参数多、有必填/选填、构造过程有顺序约束。

User u = User.builder()
    .id(1)
    .name("Ada")
    .email("a@x")
    .build();

和工厂: 工厂关注 造哪个类;建造者关注 怎么把同一个复杂对象填满。

例子: StringBuilder(更像流畅接口);Lombok @Builder;MyBatis SqlSessionFactoryBuilder;HTTP 请求 Request.Builder。

面试别把 Builder 和「链式 setter」混为一谈: 真 Builder 通常有 build() 做校验,可生成不可变对象。


3.6 原型 Prototype

问题: 创建成本高(深拷贝配置、游戏单位、报表模板),或要避开复杂构造。

Java:Cloneable + clone()。面试重点是 浅拷贝 vs 深拷贝。

例子: Object.clone;Spring BeanDefinition 的拷贝;原型 Bean(scope=prototype 每次都是新实例,名字像但不是 GoF 原型)。

讲清楚:GoF 原型是「克隆已有实例」;Spring prototype scope 是「每次向容器要都 new」,机制不同。


4. 结构型详解

4.1 适配器 Adapter

问题: 现成类接口对不上,又不能改对方(第三方、遗留)。

  • 对象适配器(组合,推荐): Adapter 持有 Adaptee,实现 Target
  • 类适配器(继承,Java 少见,单继承限制)
interface Target { void request(); }
class Adapter implements Target {
    private final Legacy adaptee;
    public void request() { adaptee.oldCall(); }
}

例子: InputStreamReader(字节流 → 字符流);Arrays.asList;Spring MVC HandlerAdapter;SLF4J 适配各种日志实现。


4.2 桥接 Bridge

问题: 有 两个独立变化维度,用继承会类爆炸(形状 × 颜色 × 渲染引擎)。

把「抽象」和「实现」拆开,用组合连起来。

Shape ──持有──> DrawingAPI
Circle / Rect          VectorAPI / RasterAPI

和适配器: 适配器是事后补丁(已有接口不匹配);桥接是事先设计(预防两维耦合)。

例子: JDBC:应用代码面向 Driver 抽象,具体 MySQL/PG 驱动是实现;图形 UI。


4.3 组合 Composite

问题: 树形结构,客户想对叶子和容器调用同一套操作。

Component ← Leaf / Composite(children)

例子: 文件系统目录;GUI 控件树;组织架构;菜单/权限树;DOM。

追问: 透明 vs 安全?
透明:Component 上就有 add/remove,叶子空实现或抛异常。安全:只有 Composite 有子节点方法,客户要转型。


4.4 装饰器 Decorator

问题: 给对象动态加职责,且要能叠加,避免子类爆炸。

装饰器和被装饰者实现同一接口,构造器包一层,调用前后加行为。

InputStream in = new BufferedInputStream(new GZIPInputStream(new FileInputStream(f)));

例子: Java IO 全家桶;Servlet HttpServletRequestWrapper;Spring TransactionInterceptor 这类增强(和代理常一起出现);Java I/O、Collections 的 unmodifiableXxx 有装饰味道。

和继承: 继承是编译期静态加功能;装饰是运行时任意组合。


4.5 外观 Facade

问题: 子系统 API 又多又乱,给上层一个粗粒度入口。

例子: JdbcTemplate(盖住获取连接、异常翻译、关闭);公司网关对内封装一堆微服务;Slf4j 外观也可以这么讲。

和适配器: 适配器转换接口;外观降低复杂度、不一定换接口。
和中介者: 外观是单向简化(客户 → 子系统);中介者是同事之间互相协作的中枢。


4.6 享元 Flyweight

问题: 大量相似对象撑爆内存。把 内部状态(可共享) 和 外部状态(场景相关) 拆开。

例子: Java Integer 缓存 [-128, 127];字符串常量池;编辑器里字符的字形对象;游戏里树的网格共享。

追问: 享元一定不可变吗?
共享部分必须不可变(或线程安全),否则会互相踩。


4.7 代理 Proxy

问题: 不能/不想直接访问真实对象:远程、懒加载、权限、日志、事务、缓存。

种类 作用
虚拟代理 懒创建大对象
远程代理 本地代表远程(RPC stub)
保护代理 权限
智能引用 引用计数、锁
静态代理 手写包装类
动态代理 JDK 接口代理 / CGLIB 子类 / ByteBuddy
// JDK 动态代理要求目标实现接口
Proxy.newProxyInstance(cl, new Class[]{Foo.class}, (p, m, args) -> {
    // before
    Object r = m.invoke(real, args);
    // after
    return r;
});

Spring AOP: 有接口默认 JDK 代理,否则 CGLIB。事务、缓存、异步都是代理。

装饰 vs 代理(必考):

装饰器 代理
目的 增强功能,对客户透明叠加 控制访问,常隐藏真实对象
持有 通常对外暴露被装饰者,可多层 经常自己创建/独占 real subject
接口 同一接口 同一接口
典型 IO 套娃 RPC、权限、懒加载、AOP

可以说:结构很像,意图不同。AOP 两者味道都有,面试说「以代理为主,用来做横切」最稳。


5. 行为型详解

5.1 策略 Strategy

问题: 同一件事多种算法,运行时选,避免满屏 if-else。

Context 持有 Strategy,可注入/可替换。

interface Discount { Money apply(Order o); }
class VipDiscount implements Discount { ... }
class Context {
    private Discount d;
    Money pay(Order o) { return d.apply(o); }
}

例子: 比较器 Comparator;Spring 的 Resource 加载策略;支付渠道、计价、风控规则。

落地: Spring 里 Map<String, Discount> 注入所有实现,按 type 取。这是面试项目里最容易讲圆的模式。

开闭: 加新策略加类,不改老策略。上下文若用反射/配置注册,连上下文都不用改。


5.2 模板方法 Template Method

问题: 流程骨架稳定,某几步各不相同。

abstract class AbstractImporter {
    public final void importFile(File f) { // 防篡改骨架
        parse(f);
        validate();
        save();
        hook(); // 可选钩子
    }
    abstract void parse(File f);
    void hook() {}
}

例子: HttpServlet.service → doGet/doPost;JUnit 生命周期;Spring JdbcTemplate 回调;抽象类里的 ApplicationListener 流程。

策略 vs 模板(必考):

策略 模板方法
复用手段 组合 继承
变化粒度 整段算法 算法中的步骤
耦合 松 继承,较紧
选择 优先策略(组合优于继承) 骨架强约束时用模板

5.3 观察者 Observer / 发布订阅

问题: 一对多依赖,主体变了通知观察者,主体不需要知道观察者是谁。

interface Observer { void on(Event e); }
class Subject {
    List<Observer> obs;
    void setState(...) { obs.forEach(o -> o.on(e)); }
}

Observer vs Pub/Sub:
观察者:Subject 直接持有 Observer 列表(耦合在「谁订阅了我」)。
发布订阅:中间有 EventBus / MQ,发布者和订阅者完全解耦。面试可以说 Pub/Sub 是观察者的解耦升级。

例子: java.util.Observer(已过时);Swing 监听器;Spring ApplicationEvent + @EventListener;Guava EventBus;Kafka 是分布式 pub/sub。

追问: 同步还是异步?异常怎么办?通知顺序?
好回答:默认同步,阻塞发布者;可用线程池异步;要事务内一致性用同步并小心回滚;Spring @TransactionalEventListener(AFTER_COMMIT) 常被追问。


5.4 责任链 Chain of Responsibility

问题: 多个对象都可能处理请求,发送者不指定具体处理者。

Handler 里 if (can) handle else next.handle。

例子: 过滤器链 Servlet Filter / Spring HandlerInterceptor / Tomcat Pipeline;网关鉴权-限流-路由;审批流;异常处理链;日志 Level。

和装饰: 装饰强调叠加增强且通常都会执行;链强调「谁处理、能否短路」。Filter 两者都像,按「能 pass 也能 reject」讲成责任链更准。


5.5 命令 Command

问题: 把「请求」做成对象,从而能排队、撤销、日志、宏命令。

Command.execute() / undo();Invoker 不关心 Receiver。

例子: 线程池 Runnable/Callable 是最简命令;GUI 按钮;编辑器撤销栈;任务队列;Netflix Hystrix 命令;CQRS 里的 Command。

和策略: 策略是可替换算法,通常不记录历史;命令是一次操作的对象化,常带撤销/队列。


5.6 状态 State

问题: 对象行为随内部状态剧烈变化,if 状态码会膨胀。

每个状态一个类,handle(context) 里可能切换 context.setState(...)。

例子: 订单(待支付/已支付/已发货/退款中);TCP 状态机;工作流引擎。

状态 vs 策略: 策略由外部注入、彼此不知道;状态知道下一个状态是谁,转换规则在状态机内部。策略不改上下文身份;状态改变的是对象「现在是什么」。


5.7 迭代器 Iterator

问题: 遍历与容器实现解耦。

hasNext/next。增强 for、Stream 都建立在这套抽象上。

例子: Collection.iterator();MyBatis 游标;数据库 cursor。

知道 fail-fast(modCount)即可。


5.8 中介者 Mediator

问题: 对象网状引用(每个人都认识所有人),改成星型:只认识中介。

例子: UI 对话框各控件;机场塔台;聊天室服务器;MQ 某种程度上是分布式中介;Spring ApplicationContext 作为对象协作中心也可以浅提。

代价: 中介容易变成上帝类,要拆。


5.9 备忘录 Memento

问题: 快照 + 回滚,且不破坏封装(别把所有字段 public)。

Originator 创建 Memento;Caretaker 只保管不拆开。

例子: 编辑器撤销;事务回滚(数据库 undo);游戏存档;浏览器历史。

注意: 快照内存成本;深浅拷贝。


5.10 访问者 Visitor

问题: 对象结构稳定(多种元素),但操作经常新增。用双分派:element.accept(visitor) → visitor.visit(concrete)。

例子: 编译器 AST 上做类型检查/代码生成;IDE 重构;表达式树求值。

代价: 每加一种元素,所有 Visitor 都要改。结构常变就别用。面试能讲清双分派就够,现场写代码很少要求。


5.11 解释器 Interpreter

用类表示文法规则。SQL 引擎、正则、规则引擎有这味。业务里少手写。知道「适合简单文法,复杂请用解析器生成器」即可。


6. 面试最高频对比(背这一页)

6.1 工厂方法 vs 抽象工厂 vs 建造者 vs 简单工厂

  • 简单工厂:一个类 switch,类型少
  • 工厂方法:一个产品,子类决定
  • 抽象工厂:一套产品族
  • 建造者:同一个复杂对象的组装过程

6.2 适配器 vs 桥接 vs 外观 vs 代理 vs 装饰

模式 核心意图
适配器 接口转换(已有的变可用的)
桥接 两维独立变化(预防类爆炸)
外观 简化一堆子系统
代理 控制访问
装饰 叠加职责

口诀:适配补接口,桥接拆两维,外观做门面,代理看门,装饰添功能。

6.3 策略 vs 状态 vs 命令 vs 模板

  • 策略:算法可互换,调用方选
  • 状态:行为由内部状态驱动,自己转移
  • 命令:请求对象化(队列/撤销)
  • 模板:继承上的流程骨架

6.4 观察者 vs 中介 vs 责任链

  • 观察者:1 对 N 通知
  • 中介:N 对 N 协作改走中心
  • 责任链:1 对「未知的那个处理者」,可短路

7. JDK / Spring 对照表(非常加分)

把模式落到「你每天用的 API」,比默写 UML 有用。

模式 JDK / 语言 Spring / 框架
单例 Runtime、enum 默认 Bean scope
工厂方法 Collection.iterator、Integer.valueOf BeanFactory、FactoryBean
抽象工厂 DocumentBuilderFactory、JDBC xxxTemplate 配套对象
建造者 StringBuilder、Stream.Builder BeanDefinitionBuilder
适配器 InputStreamReader、Arrays.asList HandlerAdapter、AdviceAdapter
装饰 BufferedInputStream 等 IO HttpServletRequestWrapper、部分 Advice
代理 动态 Proxy AOP、事务、@Async、OpenFeign
外观 java.util.logging 对 JUL JdbcTemplate、RestTemplate
享元 Integer 缓存、String intern 作用不大,可提连接池是资源复用不是标准享元
组合 Swing 组件树、NIO 少 菜单树、权限树业务代码
观察者 PropertyChangeListener ApplicationEvent
策略 Comparator、ThreadPoolExecutor 拒绝策略 Resource、InjectionStrategy
模板方法 AbstractList、Servlet JdbcTemplate、AbstractApplicationContext.refresh
责任链 Filter DispatcherServlet 拦截器、Security FilterChain
迭代器 Iterator、Stream Repository 遍历
命令 Runnable RedisTemplate 的 SessionCallback 可类比
状态 Thread.State 枚举(弱) 订单状态机(业务)
中介 — ApplicationContext 可浅比

8. 项目里怎么讲(准备 2~3 个故事就够)

面试官最烦「我们用了 23 种」。准备 2 个深的 比 10 个浅的强。

故事 A:策略消除支付 / 促销 if-else

促销规则经常加。最早 if (type==VIP) 堆在一个类,每次需求都改这段还容易回归。抽 PromotionStrategy,Spring 按 beanName 注入 Map,配置中心发类型。新活动加一个类 + 配置,核心下单代码不动。代价是类变多,所以只对「变化频繁的规则」抽,运费这种一年不变的没抽。

可被追问:策略放哪、怎么路由、怎么灰度、错误的 type 怎么办(默认策略 / 明确失败)。

故事 B:责任链做网关 / 下单校验

下单要登录校验、库存、优惠券、风控、限额。用链,每段一个 Handler,失败短路。新增「未成年人校验」只加一环。和 Filter 一样。要注意顺序和幂等。

故事 C:模板方法做数据导入

Excel / CSV / API 三种导入,校验和落库一样,解析不同。AbstractImportTemplate 定骨架,子类实现 parse。后来发现解析差异变大、骨架也在变,部分改成策略 + 组合,避免继承树僵化。——这句话展示你知道模板的代价。

故事 D:观察者做解耦

下单成功后要发积分、发短信、写审计。如果全写在 OrderService 里违反单一职责。发 OrderPaidEvent,各监听者自己干。坑:同步监听拖垮下单、监听里再开事务、失败重试。后来改 MQ,保证最终一致性。

故事 E:代理 / AOP

接口耗时、鉴权用注解 + AOP,业务方法保持干净。坑:自调用不走代理(this.foo()),要暴露 self 或 AopContext。

讲项目时主动提 坑,比只提模式名更像做过。


9. 高频问答速查

Q:有必要用设计模式吗?
A:模式是沟通词汇和针对特定变化的成熟解。没变化就不要套。我先看变化点再决定。

Q:单例有哪些坑?
A:反射、反序列化、克隆会破唯一性(enum 最稳);DCL 要 volatile;多 ClassLoader 各一份;集群不是一份;测试困难;误当共享可变数据导致并发 bug。

Q:Spring 用了哪些模式?
A:按上面对照表说 6~8 个并各举一真实类,不要背 20 个。优先:单例 Bean、工厂、代理 AOP、模板 JdbcTemplate、观察者事件、适配器 HandlerAdapter、责任链拦截器。

Q:JDK 动态代理和 CGLIB 区别?
A:JDK 只能代理接口,基于 InvocationHandler;CGLIB 继承类,final 方法和类不行;Spring Boot 2+ 有时默认 CGLIB。调用 final/private 不会被增强。

Q:装饰和代理代码都是包装,怎么选?
A:看意图:给对象加职责且希望组合 —— 装饰;控制访问、懒加载、远程、权限、事务 —— 代理。装饰常由客户组装链条;代理常对客户隐藏真实对象。

Q:如何避免过度设计?
A:Rule of three:第一次硬写,第二次皱眉,第三次再抽象。抽象要对准稳定的变化轴。加层数会伤害可读性和调试。

Q:组合优于继承,那模板方法还用吗?
A:用,但当骨架真的稳定。骨架一变,所有子类跟着炸,这时改为策略或钩子委托。

Q:空对象模式 Null Object?
A:非 GoF 但常提。用什么都不做的实现代替 null,少 NPE 和 if。和策略很配(默认策略)。

Q:MVC / MVVM 是设计模式吗?
A:是架构模式,粒度比 GoF 大。可以说「表现层架构,内部仍会用观察者(视图监听模型)」。

Q:依赖注入是什么模式?
A:不是 GoF 23。是控制反转的实现,常配合工厂(容器)和单例。它让策略/适配器更好注入。


10. 现场白板怎么画(够用就行)

不要画满 23 个 UML。任选一个讲透:

  1. 画接口 + 两个实现 + 上下文(策略最容易画)
  2. 指出客户依赖的是接口
  3. 说出加第三种实现时改哪些文件(理想:只加类,不改旧类)
  4. 补一句测试怎么 mock 接口

策略模式白板 2 分钟就能画完,是最稳的现场题。


11. 复习优先级(时间不够按这个砍)

必须能讲 10 分钟: 单例(含 DCL/volatile/enum)、工厂 vs 抽象工厂、策略、模板、代理 vs 装饰、观察者、责任链、适配器。再加上 SOLID、Spring 对照、一个项目故事。

能辨认、能对比即可: 建造者、桥接、外观、组合、状态、命令、中介、享元。

点到为止: 访问者、解释器、原型、迭代器、备忘录。


12. 30 秒自我介绍版(可直接说)

设计模式我主要当「变化点的词汇」用,不是为了用而用。创建型里单例和工厂在框架里天天见;结构型里适配器、代理、装饰分得清;行为型里策略、模板、观察者、责任链在业务里用得最多。项目里我用策略拆过分期计价,用事件把下单后的副作用拆出去,也踩过 AOP 自调用不生效。原则是:对准频繁变化的那一轴再抽象,并且能说清代价。

把其中「分期计价 / 下单事件」换成你自己仓库里的真实模块即可。


附录:一页作弊条

变化的是「具体类」     → 工厂 / 抽象工厂
变化的是「构造过程」   → 建造者
变化的是「实例数量」   → 单例
变化的是「接口」       → 适配器
变化的是「两维」       → 桥接
变化的是「树结构」     → 组合
变化的是「附加能力」   → 装饰
变化的是「访问控制」   → 代理
变化的是「子系统复杂度」→ 外观
变化的是「算法」       → 策略
变化的是「算法步骤」   → 模板
变化的是「对象状态」   → 状态
变化的是「谁来处理」   → 责任链
变化的是「通知谁」     → 观察者
变化的是「互相调用网」 → 中介
变化的是「一次操作」   → 命令

文档版本:面试向精讲(GoF 23 + SOLID + JDK/Spring 映射 + 项目话术)。
建议用法:先背第 6、7、11 章,再按第 3–5 章把「必须能讲」的 8 个模式各讲一遍给自己听,最后用第 8 章改成你的项目。