
说实话第一次准备设计模式考试的时候我真被23种设计模式吓了一跳。每种模式有名字、有结构图、有适用场景、有优缺点硬背两三天考完就忘。后来在项目和面试里反复用到才慢慢总结出一套自己的速记方法——先搭框架再记细节最后用口诀把名字串起来。这篇文章就把这套方法整理出来无论你是期末复习、面试突击还是想系统建立对设计模式的整体认知都能直接拿去用。我会尽量用大白话讲清楚每种模式的“一句话本质”再配上高频考点的代码示例和易错点争取让你看完就能照着复现。设计模式这东西本质上就是前辈们在长期开发中总结出来的“套路”。它不是语法不是框架而是一套解决特定问题的代码组织方式。学会它你看到一段代码就能猜出作者想干什么不会它你看谁写的代码都像一团乱麻。所以不管是应付考试还是真想提升内功这23个模式都值得花点时间吃透。1. 先建框架一张思维导图看懂23种设计模式1.1 设计模式到底在解决什么问题设计模式的鼻祖是GoFGang of Four四人组他们在《设计模式可复用面向对象软件的基础》里总结了23种模式。这23种模式看着多但归类之后其实非常清晰它不是按难度分的而是按“解决的问题类型”分的。创建型模式解决“对象怎么创建”的问题。说白了就是怎么new对象更合理、更灵活。结构型模式解决“类和对象怎么组合”的问题。就是怎么把多个类组织起来形成更大的结构。行为型模式解决“对象之间怎么协作”的问题。就是多个对象互相调用、互相通知时怎么把耦合降到最低。判断方法也简单你写代码时如果头疼的是“这个对象怎么来”那就是创建型如果头疼的是“这些类关系太乱、耦合太重”那就是结构型如果头疼的是“对象之间互相调用太复杂、状态老变”那就是行为型。1.2 三分钟建立起分类记忆我第一次背的时候就吃了硬背的亏后来发现必须先记“地图”。23种模式分布如下创建型5种工厂方法、抽象工厂、单例、建造者、原型结构型7种适配器、装饰器、代理、外观、桥接、组合、享元行为型11种策略、模板方法、观察者、迭代器、责任链、命令、备忘录、状态、访问者、中介者、解释器给你一个顺口溜我到现在面试写白板都靠它创建工抽单建原工厂方法、抽象工厂、单例、建造者、原型结构适装代外桥组享适配器、装饰器、代理、外观、桥接、组合、享元行为策模观迭责命备状访中解策略、模板方法、观察者、迭代器、责任链、命令、备忘录、状态、访问者、中介者、解释器还有个容易踩的坑网上很多文章会把“简单工厂”也算进去但GoF官方23种设计模式里根本没有简单工厂它只是工厂方法的一种简化写法。期末考试如果出填空题你写“简单工厂”很可能不给分。2. 创建型模式速记5种模式一套逻辑2.1 工厂三兄弟简单工厂、工厂方法、抽象工厂这三个是创建型里头最容易混的先说我的记忆锚点。简单工厂一个工厂类根据参数switch创建不同产品。优点是写起来快缺点是加一个产品就要改工厂违反开闭原则。适合产品种类少、基本不变的场景。注意它不属于GoF 23。工厂方法把工厂类抽象成接口每个具体产品对应一个具体工厂。加新产品时只需要新增一个产品和对应工厂不用改老代码。C里最典型的样子长这样class Product { public: virtual void use() 0; }; class ConcreteProductA : public Product { public: void use() override { /* ... */ } }; class Factory { public: virtual Product* createProduct() 0; }; class ConcreteFactoryA : public Factory { public: Product* createProduct() override { return new ConcreteProductA(); } };抽象工厂工厂方法负责生产“一种产品”抽象工厂负责生产“一族产品”。比如一个餐厅既卖汉堡又卖可乐那抽象工厂就是“连锁品牌”它规定“你这一整套菜单必须包含汉堡、薯条、可乐”至于怎么实现看具体分店。怎么区分简单工厂看参数返回不同对象工厂方法是每个产品配一个工厂抽象工厂是一个工厂返回一族有关联的对象。考试和面试最喜欢问这个问题你把“一族产品”这四个字记住抽象工厂就抓住了核心。2.2 单例模式懒汉、饿汉、双检锁单例模式面试出现频率极高尤其喜欢问Double-Checked Locking。先看标准答案。饿汉式类加载时就创建实例线程安全但可能造成不必要的资源浪费。代码很简单public class Singleton { private static final Singleton INSTANCE new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }懒汉式第一次调用时才创建但是线程不安全。给方法加synchronized能解决但性能太差。所以有了双检锁public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance null) { synchronized (Singleton.class) { if (instance null) { instance new Singleton(); } } } return instance; } }面试最爱问为什么加volatile因为instance new Singleton()不是原子操作它分三步分配内存、初始化对象、把引用指向内存。如果不加volatile编译器可能重排序成“先指向内存、再初始化对象”另一个线程就会拿到一个没初始化完的半成品。简单理解就是volatile禁用了重排序保证看到的是完整对象。实际开发我一般推荐枚举单例代码最简洁还能防反射攻击和序列化破坏。2.3 建造者模式专治构造函数参数爆炸建造者模式解决的是“一个对象参数太多、构造方法太乱”的问题。比如一个电脑类有CPU、内存、硬盘、显卡、显示器十几个可选参数你写十几个构造函数那维护起来就是灾难。建造者的思路是把对象的构建过程拆分成一步步的build方法最后通过build()组装Computer computer new Computer.Builder() .cpu(i7) .memory(16G) .disk(1T SSD) .build();Java里很常见的Lombok Builder注解、OkHttp的Builder、Spring的BeanDefinitionBuilder都是这个套路。面试问它你就说“解决多参数构造和对象属性过多的问题同时保证对象创建过程清晰”。注意建造者模式和工厂模式的区别工厂模式关心“造出哪个产品”建造者模式关心“这个复杂产品怎么一步步拼出来”。还有一种容易忽略的场景当一个对象创建完之后不应该被修改时建造者模式配合不可变类非常好用构造过程灵活最终对象还是不可变的。2.4 原型模式浅拷贝深拷贝的坑原型模式的核心是“复制现有对象而不是new”。Java里就是实现Cloneable接口重写clone()方法。它省去了重新初始化的开销适合创建成本高、对象状态差别不大的场景。但原型模式最容易踩的坑就是浅拷贝和深拷贝的区别。默认clone()是浅拷贝对象内部的引用类型还是指向同一个对象你改了一个对象的子对象另一个也跟着变。解决方法是重写clone()时把内部的可变对象也手动clone一遍或者用序列化的方式实现深拷贝。面试问原型模式一般会追问深浅拷贝区别你把“浅拷贝只拷引用、深拷贝连内部对象一起复制”记住再用“数组里的对象修改会互相影响”举例就够了。3. 结构型模式速记7种模式两种套路3.1 适配器、装饰器、代理三个最容易混的模式这三个模式代码长得很像面试时特别容易说串。我的记忆方法是“三个生活比喻”。适配器模式就是转接头。Type-C转USB、插座转换器作用是把一个接口转换成客户期望的另一个接口。比如老系统的接口是220V新系统要110V中间加一个适配器。代码上就是“包装一个对象把A接口转成B接口”。装饰器模式就是手机壳。它不改变接口只是在原有功能上叠加增强。Java的IO流是经典例子new BufferedReader(new FileReader(...))一层套一层每个装饰器加一点功能但接口始终是Reader。核心特征是“接口不变功能增强”。代理模式就是经纪人。它也不改变接口但目的是“控制访问”而不是增强功能。比如真正的对象不想让别人直接访问或者访问前要做权限校验、日志记录就通过代理。Spring AOP、MyBatis的Mapper动态代理都是代理模式。代理和装饰器长得几乎一样区别在意图装饰器只是想给对象“加功能”代理是想“控制对象怎么被访问”。面试官问你怎么区分你就说“看目的装饰器重功能增强代理重访问控制”。3.2 外观、桥接、组合、享元四个整理关系的模式外观模式是遥控器。你把一堆复杂子系统封装成一个简单门面外部只跟门面打交道。比如一个家庭影院要开投影、开音响、拉窗帘你封装成一个oneKeyPlay()方法外面调一个方法就行。它最重要的价值是降低使用方的复杂度不改变子系统本身的功能。桥接模式是抽象与实现分离。典型例子是JDBC的DriverManagerJava定义了一套数据库接口具体实现由各数据库厂商提供两边通过桥接解耦。它解决的是“多个维度变化”的问题比如形状和颜色如果用继承就是N种形状乘以M种颜色用桥接就是两个维度独立扩展。组合模式是树形结构。文件系统、公司组织架构、菜单层级都是组合模式。核心思想是“部分和整体有一致性”单个文件和文件夹都能调用同一个方法。大话设计模式里的例子就很经典总公司有子公司子公司有部门一层层往下都算“组织节点”。这样客户端调用时不需要区分是叶子节点还是容器节点。享元模式是池化思想。String常量池、线程池、数据库连接池都是享元模式。它把可共享的对象缓存起来重复使用避免重复创建造成内存浪费。核心是区分“内部状态”可共享和“外部状态”不可共享。面试只要说出“线程池、字符串常量池就是享元模式的典型应用”基本就过关了。3.3 结构型模式做题判断技巧期末考或面试时给一段代码让你判断用了什么模式我的判断顺序是如果代码里出现了“接口转换”优先想适配器。如果出现了“包了一层又一层接口没变”想装饰器。如果出现了“代理对象实际干活的是被代理对象”想代理。如果出现“一个类封装了多个子系统”想外观。如果出现“一个接口多个实现客户端只面向接口”先想桥接。如果出现“树形结构递归”想组合。如果出现“对象池/缓存复用”想享元。4. 行为型模式速记11种模式分清职责4.1 三个最常用的策略模式、模板方法、观察者模式策略模式本质是“把算法封装起来客户端可以随时切换”。Java里的Comparator就是最典型的例子。用策略模式做打折计算可以让满减、折扣、立减各自实现同一个策略接口业务代码里传入不同的策略对象即可。它的好处是完全符合开闭原则新增一种优惠方式不用改老代码只加一个类。模板方法模式本质是“父类定义流程子类实现细节”。比如做奶茶步骤固定是“煮茶、加料、封装”但加什么料由子类决定。它的核心就是把不变的流程写在抽象类里把变化的步骤抽象成方法交给子类实现。面试问它你举“AbstractList的模板方法”或者“Spring的JdbcTemplate”都可以。观察者模式本质是“一对多通知”。一个主题状态变化多个观察者自动收到通知。Java的Listener、Android的点击事件、消息队列的订阅发布都是这个思路。面试必问题观察者模式和发布订阅模式什么区别简单说观察者模式是主题直接通知观察者耦合还在发布订阅读者在中间加了一个消息代理生产者和消费者完全解耦属于观察者模式的升级版。策略模式和状态模式特别容易混。策略模式是“客户主动换算法”状态模式是“对象内部状态变化自动切换行为”。一句话策略是外面换状态是自己换。4.2 责任链、命令、备忘录、状态、中介者处理流程与状态的五虎将责任链模式本质是“请求沿着链传递谁能处理谁处理”。Servlet的Filter链、SpringMVC的拦截器链、Netty的ChannelHandler链都是责任链。考试大作业如果做审批系统领导审批、经理审批、总监审批层层往上这就是责任链模式。命令模式本质是“把请求封装成对象”。好处是可以排队、可以撤销、可以记录日志。编辑器里的CtrlZ撤销就是命令模式每个操作都是一个Command对象撤销时调用undo()。Runnable接口其实也是命令模式的思想把任务封装成对象丢给线程池执行。备忘录模式本质是“保存快照支持恢复”。游戏存档、文档历史版本都是这个模式。Caretaker管理者持有快照Originator发起人负责生成和恢复快照核心是“不破坏封装的前提下保存和恢复状态”。状态模式本质是“状态决定行为”。电梯门开着能按关门关着不能按订单待支付能取消、已发货不能取消。它的核心是把每个状态的逻辑封装成一个类状态切换由类内部完成避免一堆if-else。我之前做订单系统最深的体会是订单状态一多if-else就是灾难状态模式虽然类多了点但每个状态类的逻辑非常清晰加新状态也好扩展。中介者模式本质是“多个对象不直接交互都通过中介者”。比如聊天室用户A发消息不需要直接推给B、C、D而是发给聊天室聊天室中转。它解决的是“同事对象”两两交互导致的网状依赖改成星型依赖。4.3 三个“偏门”的迭代器、访问者、解释器迭代器模式最简单就是“提供一种统一方式遍历集合不暴露内部结构”。Java的Iterator就是标准实现考试考得不多记住“遍历”两个字就行。访问者模式是设计模式里比较难懂的一个核心是“数据结构和操作分离”。比如医院里药房划价、医生诊断同一个病人被不同角色“访问”每种角色给出不同结果。但它带来的问题是增加新操作容易增加新元素难所以实际项目里用得很少面试也很少深挖。你能说出“它把稳定的数据结构和对数据的操作解耦”就算过关。解释器模式是“定义一种语言解释它的句子”。正则表达式、SQL解析、编译器都是解释器模式的思想。但它类结构非常复杂一般只在特定领域使用我做了这么多年开发几乎没有在业务代码里手写过解释器。面试问到的话举正则表达式的例子就够了。行为型11种如果觉得头大再给你一条记忆主线策模观是“最常用的三大天王”迭责命备状是“处理流程和状态的五虎将”访中解是“三个偏门选手”。5. 高频考点、面试场景与避坑清单5.1 高频面试题速查表问题一句话回答要点单例模式有哪些写法饿汉、懒汉、双检锁、静态内部类、枚举推荐枚举和双检锁工厂方法和抽象工厂的区别工厂方法生产一种产品抽象工厂生产一族产品代理模式和装饰器模式的区别代理控制访问装饰器增强功能策略模式和状态模式的区别策略是外部主动换算法状态是内部自动换行为观察者模式哪里用到事件监听、消息订阅、Spring事件机制适配器和外观模式都能“包装”别人怎么分适配器为了接口兼容外观为了简化调用静态代理和动态代理区别静态代理在编译期写死代理类动态代理在运行期生成代理类JDK动态代理基于接口CGLIB基于继承5.2 期末大作业怎么选模式如果你们课程要求“设计模式大作业”我的建议是别贪多。选一个完整场景把3到4个模式用进去就行。比如做“文件管理系统”组合模式表示目录树迭代器模式遍历文件观察者模式通知文件变化命令模式实现撤销删除。再比如“网上订餐系统”工厂方法创建不同类型的餐品策略模式计算优惠价格状态模式管理订单状态责任链模式做订单审核。最推荐的是组合模式做公司组织架构或文件目录因为树形结构天然适合组合模式画出来的类图也清晰答辩时好讲评委也容易理解。5.3 我踩过的几个坑第一个坑是死记类图。设计模式考的不是类图画得多标准而是你能不能讲清楚“为什么这么设计”。对着类图背十遍不如亲手写一遍策略模式不信你试试。第二个坑是误以为用设计模式就是好代码。我见过有人为了用模式而用模式简单功能硬套一个抽象工厂最后类爆炸了维护更痛苦。设计模式的本质是解决特定问题抽象是要付出代价的类多了、调用链复杂了、读代码的负担也重了。没有那个问题就别硬套。第三个坑是面试时只背名字。面试官问“你用过哪些设计模式”你别只答“单例、工厂、代理”。正确姿势是先说项目中某个具体场景再说用了什么模式最后说解决了什么问题。比如“我在订单模块里因为订单状态多、分支乱用状态模式重构后if-else少了很多加新状态只需要新增状态类”。设计模式这东西光看是看不熟的。我自己也是项目里踩过几次坑、重构过几轮代码之后才真正明白“面向接口编程”“组合优于继承”这些原则到底在说什么。你把这23种模式背下来只是第一步第二步是在自己的项目里找到能用的地方哪怕只是把一个switch换成策略模式你都会比昨天进步一点。祝期末顺利面试顺利。