2026/10/24 16:27:45

设计模式复习指南:从七大原则到代码落地的闭环方法

设计模式复习指南:从七大原则到代码落地的闭环方法 简介这份《大话设计模式复习》文档面向具备一定面向对象编程基础、工作1至3年的研发人员系统梳理设计模式的核心知识体系。内容从设计模式的定义、分类、特点与应用场景切入详细讲解单一职责、开放-封闭、依赖倒转、里氏代换、迪米特法则、合成/聚合及接口隔离七大设计原则并深入剖析抽象工厂、策略、外观、适配器、组合、单例、中介者七种常用模式以及其余十五种模式每种均配以定义、UML类图、基础代码与实例说明。文档还横向对比不同模式的差异总结模式选择的关键维度并附练习题与模拟试卷辅助巩固。资源包为单个docx文件大小约3.66MB目录结构清晰便于按章节检索学习。目前已有191人学习适合希望提升代码可维护性、可扩展性与复用能力并在实际项目中灵活选用设计模式的开发者参考。1. 从一份复习文档说起为什么设计模式总在“面试造火箭入职拧螺丝”很多人对设计模式的认知是从面试前夜翻八股文开始的。背了一堆“开闭原则”“里氏代换”真到项目里写业务代码还是if-else一把梭。这份《大话设计模式复习》文档的价值不在于它又列了一遍 23 种模式的定义而在于它把“定义—UML 类图—基础代码—实例—优缺点—违反哪条原则”串成了一条完整的复习链路还附了模式对比表和模拟试卷。它适合工作 1-3 年、面向对象基础还在但设计经验偏弱的开发者尤其是准备跳槽或想系统梳理 Java 设计模式的人。我拿到这份文档后没有直接通读而是按“七大原则 → 七大重点模式 → 剩余模式 → 对比表 → 试卷”的顺序拆了一遍下面把拆解过程和落地方法写清楚。2. 七大设计原则先立规矩再看模式怎么“守规矩”2.1 原则不是口号是判断模式好坏的标尺文档开篇把七大原则放在模式之前这个顺序是对的。很多人学模式只记结构不记原则结果用工厂模式写出一个“每加一个产品就要改工厂类”的代码还觉得自己用了设计模式。实际上抽象工厂模式在文档里被明确标注“违反开放-封闭原则”——新增产品等级结构时抽象工厂和所有具体工厂都要改。这不是说抽象工厂不好而是说它有明确的适用边界产品族稳定、产品等级结构不常变时才划算。七大原则里最容易被误解的是里氏代换原则。文档举了“正方形是矩形的子类”这个经典反例如果矩形有setWidth和setHeight正方形继承后设置宽高会互相影响替换矩形时行为就不一致了。所以里氏代换不是“子类能编译通过就行”而是“子类替换父类后父类的行为契约不能被破坏”。判断方法很简单客户端代码如果依赖父类的某个不变量比如面积 宽 × 高子类就不能悄悄改掉这个不变量。依赖倒转原则和合成/聚合原则是模式实现的两大支柱。依赖倒转要求高层模块和低层模块都依赖抽象文档里工厂模式的客户端依赖IUser和IDepartment接口而不是SqlserverUser具体类就是这条原则的落地。合成/聚合原则则解释了为什么装饰模式用组合而不是继承——继承是编译期绑定组合是运行期绑定装饰器可以一层层套继承只能固定层级。2.2 用一段代码验证“开闭原则”是否真的落地文档里策略模式的商场收银系统实例是验证开闭原则的好材料。正常收费、满减、打折三种策略如果写成if (type 正常) ... else if (type 满减) ...新增一种“满 1000 打 8 折”就要改if-else链违反开闭。用策略模式改写后新增策略只需加一个类客户端通过Context注入即可。// 策略接口所有收费算法的公共契约 interface CashSuper { double acceptCash(double money); } // 正常收费策略 class CashNormal implements CashSuper { Override public double acceptCash(double money) { return money; // 原价返回 } } // 满减策略满 moneyCondition 减 moneyReturn class CashReturn implements CashSuper { private double moneyCondition; private double moneyReturn; public CashReturn(double moneyCondition, double moneyReturn) { this.moneyCondition moneyCondition; this.moneyReturn moneyReturn; } Override public double acceptCash(double money) { // 只有达到满减门槛才减否则原价 if (money moneyCondition) { return money - Math.floor(money / moneyCondition) * moneyReturn; } return money; } } // 上下文持有策略对外暴露统一入口 class CashContext { private CashSuper cashSuper; public CashContext(CashSuper cashSuper) { this.cashSuper cashSuper; } public double getResult(double money) { return cashSuper.acceptCash(money); // 委托给具体策略 } } // 客户端新增策略时只加类不改这里 public class Client { public static void main(String[] args) { CashContext ctx new CashContext(new CashReturn(300, 100)); System.out.println(ctx.getResult(600)); // 输出 400.0 } }这段代码的关键参数是moneyCondition和moneyReturn分别表示满减门槛和减免金额。Math.floor(money / moneyCondition)处理的是“满 300 减 100满 600 减 200”这种可叠加场景。如果业务规则是“每满 300 减 100上不封顶”这个写法就够用如果是“满 300 减 100但只减一次”就要把Math.floor去掉。文档里 C 版本的CashReturn只做了一次判断Java 改写时我按可叠加逻辑补了floor这是实际项目里更常见的需求。提示策略模式和简单工厂结合时CashContext构造函数可以传入字符串类型内部用switch创建策略。但这样CashContext就同时承担了“创建”和“执行”两个职责违反单一职责原则。文档在对比表里也提到策略模式和状态模式容易混淆区别在于策略模式由客户端选择算法状态模式由状态自身驱动转移。3. 七大重点模式抽象工厂、单例、中介者的代码骨架与参数边界3.1 抽象工厂产品族扩展的代价在哪里文档把抽象工厂放在七大模式之首并给了可移植数据访问程序的完整实例IFactory接口声明CreateUser()和CreateDepartment()SqlServerFactory和AccessFactory分别创建SqlserverUserSqlserverDepartment和AccessUserAccessDepartment。客户端只依赖IFactory、IUser、IDepartment三个抽象切换数据库时只改一行new SqlServerFactory()为new AccessFactory()。这个实例的参数边界很清晰产品族是“User Department”产品等级结构是“SqlServer 实现”和“Access 实现”。如果新增一个“Oracle 实现”只需加OracleFactory、OracleUser、OracleDepartment符合开闭原则。但如果新增一个“Login 对象”就要改IFactory、SqlServerFactory、AccessFactory三个接口/类违反开闭。文档在优缺点里写得很直白“增加新产品的等级结构需修改抽象工厂和所有具体工厂”。所以抽象工厂的选型判断就一句话产品族稳定、产品等级结构可能扩展时用反过来产品等级结构稳定、产品族可能扩展时工厂方法更合适。// 抽象工厂接口声明创建产品族的方法 interface IFactory { IUser createUser(); IDepartment createDepartment(); } // 具体工厂SqlServer 产品族 class SqlServerFactory implements IFactory { Override public IUser createUser() { return new SqlserverUser(); // 返回具体产品 } Override public IDepartment createDepartment() { return new SqlserverDepartment(); } } // 抽象产品User 的接口 interface IUser { void insert(User user); User getUser(int id); } // 具体产品SqlServer 的 User 实现 class SqlserverUser implements IUser { Override public void insert(User user) { System.out.println(在 Sqlserver 中给 User 表增加一条记录); } Override public User getUser(int id) { System.out.println(在 Sqlserver 中根据 ID 得到 User 表一条记录); return new User(); } } // 客户端只依赖抽象切换工厂即可切换数据库 public class Client { public static void main(String[] args) { IFactory factory new SqlServerFactory(); // 改这里即可切换 Access IUser user factory.createUser(); user.insert(new User()); user.getUser(1); } }IFactory里的两个方法返回类型都是接口这是依赖倒转原则的直接体现。SqlserverUser.insert里的System.out.println只是占位实际项目里应该替换成 JDBC 或 ORM 调用。文档里User和Department类只有id、name、deptname字段和 getter/setter这是为了聚焦模式结构真实业务对象会有更多字段和校验逻辑。3.2 单例模式双重检查锁定的 volatile 不能省文档在剩余模式分析里给了单例模式但篇幅不长。单例的坑不在“怎么写”而在“怎么写对”。饿汉式在类加载时就创建实例线程安全但可能浪费资源懒汉式加synchronized性能差双重检查锁定DCL是常见折中但instance必须加volatile否则指令重排序可能导致其他线程拿到一个“半初始化”的对象。public class Singleton { // volatile 禁止指令重排序保证可见性 private static volatile Singleton instance; private Singleton() { // 私有构造防止外部 new } public static Singleton getInstance() { if (instance null) { // 第一次检查避免每次加锁 synchronized (Singleton.class) { if (instance null) { // 第二次检查防止重复创建 instance new Singleton(); } } } return instance; } }参数说明volatile在这里不是可选项。instance new Singleton()分三步分配内存、初始化对象、将引用指向内存。没有volatile时步骤 2 和 3 可能重排序线程 B 在第一次检查时看到instance ! null但对象还没初始化完直接使用就会出问题。文档里没有展开这一点但这是单例模式最经典的“血泪经验”。3.3 中介者模式同事类不直接通信中介者承担转发文档把中介者模式放在七大模式里和迪米特法则直接对应。迪米特法则要求“两个类若不必直接通信则不发生直接作用”中介者模式就是这条原则的落地同事类只持有中介者引用所有交互通过中介者转发。文档里的 UML 类图显示Mediator抽象类声明Colleague之间的通信方法ConcreteMediator持有多个ConcreteColleagueColleague抽象类持有Mediator引用。实际项目里中介者模式常用于 UI 组件联动按钮点击后文本框、下拉框、状态栏都要更新如果按钮直接持有其他组件引用耦合会爆炸。用中介者后按钮只通知中介者中介者决定通知谁。代价是中介者可能变成“上帝类”所以文档在对比表里把中介者和责任链放在一起对比责任链是链式传递中介者是星型转发前者适合审批流后者适合组件联动。4. 剩余 15 种模式对比表比逐个背定义更有用4.1 创建型模式对比简单工厂 vs 工厂方法 vs 抽象工厂文档最后一部分的模式对比表是整份资料里最值得反复看的内容。创建型模式里简单工厂、工厂方法、抽象工厂的区别可以用一张表说清维度简单工厂工厂方法抽象工厂工厂数量一个工厂类每个产品一个工厂类每个产品族一个工厂类产品维度单一产品等级单一产品等级多个产品等级产品族新增产品改工厂类违反开闭加工厂类符合开闭改抽象工厂违反开闭适用场景产品少且稳定产品扩展频繁产品族稳定、族内产品一起用简单工厂的switch是“后悔药”最多的地方产品少时写着快产品一多就变成几百行case。工厂方法把switch拆到各个工厂类里新增产品不影响已有代码。抽象工厂则是在工厂方法基础上加了“产品族”维度适合数据库访问、跨平台 UI 组件这类场景。4.2 结构型模式对比适配器、装饰器、代理的边界文档把适配器、装饰器、代理放在一起对比这三个模式结构相似但意图完全不同。适配器是“接口转换”让不兼容的接口能一起工作装饰器是“功能增强”在不改原类的前提下叠加功能代理是“访问控制”在客户端和目标对象之间加一层间接层控制访问权限或延迟加载。判断方法如果客户端需要的是“另一个接口”用适配器如果需要“同样的接口但功能更多”用装饰器如果需要“同样的接口但访问受控”用代理。文档里组合模式和装饰器模式的对比也值得注意组合模式是“整体-部分”树形结构装饰器是“一层套一层”的链式结构前者用于树形菜单、文件系统后者用于 IO 流、权限校验链。4.3 行为型模式对比策略 vs 状态、观察者 vs 中介者策略模式和状态模式的类图几乎一样区别在“谁决定切换”。策略模式由客户端选择算法Context不关心算法怎么变状态模式由状态自身决定下一个状态Context只是状态转移的载体。文档里责任链模式和中介者模式的对比也很实用责任链是“请求沿链传递直到被处理”中介者是“请求发给中心由中心转发”前者适合审批流、过滤器链后者适合 UI 联动、聊天室。观察者模式和中介者模式容易混观察者是“一对多”依赖主题通知所有观察者中介者是“多对多”协调同事之间不直接通信。文档在对比表里把这两组都列出来了复习时先看对比表再回头看具体模式的 UML 和代码效率比从头逐个背高得多。5. 避坑与排查复习设计模式时最容易翻车的五个点5.1 现象背了 23 种模式写代码还是if-else堆砌原因只记了模式结构没记模式要解决的具体问题。文档里每个模式都有“适用场景”和“应用原则”但复习时容易跳过。解决每学一个模式强制问自己“不用这个模式代码会变成什么样”。比如策略模式不用它时if-else链会随折扣类型增加而膨胀用了它新增折扣只加类。把“不用模式的坏处”写下来比背定义管用。5.2 现象抽象工厂新增一个产品所有工厂类都要改原因抽象工厂的固有缺陷文档在优缺点里已经写明“增加新产品的等级结构需修改抽象工厂和所有具体工厂”。解决选型时先判断“产品族稳定还是产品等级结构稳定”。如果产品等级结构如 User、Department稳定产品族如 SqlServer、Access可能扩展用抽象工厂如果产品等级结构本身会频繁新增改用工厂方法或简单工厂避免抽象工厂的“牵一发动全身”。5.3 现象单例模式在并发环境下创建了多个实例原因懒汉式没加锁或 DCL 没加volatile。解决按 3.2 的代码模板写volatile和两次null检查都不能省。如果实例创建成本不高直接用饿汉式类加载时创建简单且线程安全。文档里没有展开并发细节但这是单例模式在实际项目里最容易翻车的地方。5.4 现象装饰器和代理分不清代码结构写混原因两者都持有目标对象引用都实现同一接口。解决看意图。装饰器是“增强功能”客户端主动套多层代理是“控制访问”客户端以为在调目标对象实际调的是代理。文档里适配器、装饰器、代理的对比表可以直接拿来当检查清单接口是否改变、功能是否增强、访问是否受控三个问题问完就能选对。5.5 现象模式对比表背了但面试时说不清“为什么选这个不选那个”原因对比表只记了结论没记判断维度。解决文档最后的“模式选择关键维度”是抓手——产品族是否稳定、算法是否频繁扩展、对象交互是否复杂、是否需要控制访问。每个维度对应一组模式面试时先问清场景再按维度排除最后给出选型理由。比如“数据库访问组件产品族稳定但可能换数据库”直接对应抽象工厂“折扣算法经常新增”直接对应策略模式。6. 用模拟试卷做闭环验证一份可复现的复习节奏文档附了练习题和模拟试卷这是很多人忽略的部分。我的用法是先按“七大原则 → 七大模式 → 剩余模式 → 对比表”过一遍然后合上文档用模拟试卷限时做一遍。做题时重点看两类题一类是“给出场景选模式”一类是“给出模式写 UML 或代码骨架”。前者验证选型判断后者验证结构记忆。如果模拟试卷里“抽象工厂和工厂方法的区别”答不全就回到第 4.1 的对比表把“工厂数量、产品维度、新增产品的影响”三个维度默写一遍。如果“策略模式和状态模式的区别”说不清就回到第 4.3用“谁决定切换”这个判断点重新推一遍。文档里的代码实例不用逐行抄但每个模式的“基础代码”骨架要能默写出来抽象工厂的IFactoryIUserIDepartment策略模式的StrategyContext单例的 DCL 模板。我自己的习惯是每复习完一个模式就在模拟试卷对应题目旁边写一句“这个模式不用会怎样”。比如单例模式旁边写“不用会重复创建数据库连接资源耗尽”策略模式旁边写“不用会if-else膨胀新增折扣要改客户端”。这些句子在面试时比背定义更管用因为它们直接对应“为什么用”这个核心问题。注意文档里的 C 代码和 Java 代码混排复习时建议统一用一种语言重写。Java 开发者可以把 C 的CashSuper、CashReturn改写成 Java 版本顺便验证自己是否真的理解了虚函数和接口的区别。改写过程中如果发现某个模式的结构写不出来说明还没掌握回到 UML 类图重新推一遍。从那以后我每次复习设计模式都强制走一遍“原则 → 模式 → 对比 → 试卷”的闭环不再从头到尾通读。这份文档的价值在于它把这条闭环需要的材料都备齐了剩下的就是动手改写和默写。希望帮到你。本文还有配套的精品资源点击获取