
简介这份《大话设计模式复习》文档面向具备一定面向对象编程基础、工作1至3年的研发人员系统梳理设计模式的核心知识体系。内容从设计模式的定义、分类、特点与应用场景切入详细讲解单一职责、开放-封闭、依赖倒转、里氏代换、迪米特法则、合成/聚合及接口隔离七大设计原则并深入剖析抽象工厂、策略、外观、适配器、组合、单例、中介者七种常用模式以及其余十五种模式每种均配以定义、UML类图、基础代码与实例说明。文档还对比不同模式的差异总结模式选择的关键维度并附练习题与模拟试卷辅助巩固。资源为单个docx文件压缩包约3.66MB已有191人学习。读者可借此理解模式适用场景提升代码可维护性与复用性并在实际项目中做出更合理的设计选择。1. 从一份复习文档到可交付的设计模式方案为什么模式选型总在项目里翻车很多同学做软件工程课设或毕设时功能跑通了代码却越写越乱加一个折扣策略要改五六个文件换一个数据库实现要动客户端代码对象创建散落各处。问题不在语法而在设计模式没有落到方案层面。这份《大话设计模式复习》文档覆盖了 23 种经典模式、七大设计原则、模式对比和模拟试卷正好能当作一套完整的复习与落地参考。它适合两类人一是正在准备软件工程考试或课程设计的学生需要把抽象工厂、策略、外观、适配器、组合、单例、中介者这七种高频模式吃透二是工作 1 到 3 年、想系统梳理面向对象设计经验的开发者。下面按需求、设计、实现、避坑、验收的顺序把这份资料拆成一份可以直接照着走的方案。2. 需求与设计原则七大原则怎么约束模式选型2.1 从需求场景反推原则优先级拿到一个课设或模块开发任务第一步不是翻模式目录而是把需求里的变化点标出来。比如商场收银系统变化点在折扣算法可移植数据访问程序变化点在数据库类型。变化点确定后再对照七大设计原则做取舍。单一职责原则要求一个类只有一个引起变化的原因。收银系统里正常收费、打折、满减各自独立成类而不是塞进一个 CashSuper 里写 if-else。开放-封闭原则要求对扩展开放、对修改关闭策略模式新增一种折扣只需加一个具体策略类不改上下文。依赖倒转原则要求高层模块和低层模块都依赖抽象工厂模式里客户端依赖 IUser 接口而不是 SqlserverUser 具体类。里氏代换原则要求子类能替换父类且行为一致正方形继承矩形时面积计算逻辑不能变。迪米特法则要求减少直接交互中介者模式让同事类通过中介者通信。合成/聚合原则优先用组合而非继承装饰模式就是典型。接口隔离原则要求接口细化把动物接口拆成飞行动物和陆地动物。这七条原则不是并列关系实际项目里优先级通常是先满足单一职责和开放-封闭再用依赖倒转解耦最后用迪米特和合成/聚合降低类间依赖。接口隔离和里氏代换更多是检查项用来验证设计有没有明显违规。2.2 用 UML 类图把原则翻译成结构文档里反复出现 UML 类图抽象类用斜体表示类之间有关系连线。这一步很关键因为原则是文字类图是结构。以抽象工厂为例类图里有四层AbstractFactory 声明 createProductA 和 createProductBConcreteFactory1 和 ConcreteFactory2 分别实现AbstractProductA 和 AbstractProductB 定义产品接口ProductA1、ProductA2、ProductB1、ProductB2 是具体产品。画类图时我一般会检查三件事抽象层是否稳定具体层是否可替换客户端是否只依赖抽象。如果客户端代码里出现了 new SqlserverUser() 这样的具体类名依赖倒转就没做到。如果新增一个产品族要改 AbstractFactory 接口说明开放-封闭在抽象工厂这个方向上是有代价的文档里也明确写了这一点增加新产品的等级结构需修改抽象工厂和所有具体工厂违反开放-封闭原则。这不是设计错误而是抽象工厂的固有取舍选型时要提前知道。2.3 原则与模式的映射关系把七大原则和 23 种模式做一张映射表复习和答辩时都能用。设计原则主要约束的模式检查点单一职责策略、命令、状态每个具体类是否只有一个变化原因开放-封闭策略、工厂方法、装饰新增行为是否只加类不改原有类依赖倒转抽象工厂、工厂方法、桥接客户端是否依赖抽象接口里氏代换组合、模板方法子类替换父类后行为是否一致迪米特中介者、外观类之间是否通过中间层通信合成/聚合装饰、组合、桥接是否用组合替代了继承扩展接口隔离适配器、外观接口是否被拆成职责单一的小接口这张表的作用是反向验证如果某个模式用完后发现违反了多条原则要么是场景不匹配要么是实现方式有问题。比如用单例模式管理全局配置如果配置类同时承担了读取、解析、缓存三个职责就违反了单一职责应该拆开。3. 七大高频模式实现从抽象工厂到中介者的代码落地3.1 抽象工厂与策略模式创建族与算法族的分离抽象工厂解决的是产品族创建问题。文档里的可移植数据访问程序是典型场景IFactory 接口声明 CreateUser 和 CreateDepartmentSqlServerFactory 和 AccessFactory 分别创建对应的 User 和 Department 对象。客户端只持有 IFactory 引用切换数据库时只改一行工厂实例化代码。// 抽象工厂接口声明创建产品族的方法 public interface IFactory { IUser CreateUser(); IDepartment CreateDepartment(); } // 具体工厂SqlServer 产品族 public class SqlServerFactory implements IFactory { public IUser CreateUser() { return new SqlserverUser(); } public IDepartment CreateDepartment() { return new SqlserverDepartment(); } } // 客户端只依赖抽象工厂和抽象产品 IFactory factory new SqlServerFactory(); IUser iu factory.CreateUser(); iu.Insert(user); iu.GetUser(1);这段代码的关键在于客户端没有出现任何具体产品类名。IFactory 是抽象工厂IUser 和 IDepartment 是抽象产品SqlserverUser 和 SqlserverDepartment 是具体产品。参数说明CreateUser 返回 IUser 接口Insert 接收 User 对象GetUser 接收 int 类型 id。如果要新增一个 Oracle 产品族只需实现 OracleFactory、OracleUser、OracleDepartment客户端改一行工厂实例化即可。但如果是新增一种产品类型比如 ILogin就需要修改 IFactory 接口和所有具体工厂这是抽象工厂的代价。策略模式解决的是算法族切换问题。文档里的商场收银系统是标准案例CashSuper 是抽象策略CashNormal、CashReturn、CashRebate 是具体策略Context 持有 CashSuper 引用并委托执行。// 策略接口 public abstract class CashSuper { public abstract double acceptCash(double money); } // 具体策略满减 public class CashReturn extends CashSuper { private double moneyCondition 0; private double moneyReturn 0; public CashReturn(double moneyCondition, double moneyReturn) { this.moneyCondition moneyCondition; this.moneyReturn moneyReturn; } public double acceptCash(double money) { if (money moneyCondition) { return money - Math.floor(money / moneyCondition) * moneyReturn; } return money; } } // 上下文持有策略并委托执行 public class CashContext { private CashSuper cs; public CashContext(CashSuper cs) { this.cs cs; } public double getResult(double money) { return cs.acceptCash(money); } }参数说明moneyCondition 是满减条件moneyReturn 是减免金额acceptCash 接收原始金额返回折后金额。策略模式的核心是把算法从客户端剥离客户端只和 Context 交互。和简单工厂结合时可以在 Context 构造函数里根据字符串创建具体策略但这样 Context 就承担了创建职责需要权衡是否违反单一职责。3.2 外观、适配器与组合模式结构型模式的三种解耦方式外观模式为子系统提供统一入口。文档里的外观模式适合这样的场景一个模块内部有多个类协作完成功能外部调用者不需要知道内部细节。实现方式是创建一个 Facade 类持有子系统对象的引用对外暴露一个简化方法。// 子系统类 public class SubSystemOne { public void methodOne() { System.out.println(子系统方法一); } } public class SubSystemTwo { public void methodTwo() { System.out.println(子系统方法二); } } // 外观类组合子系统对外提供统一接口 public class Facade { private SubSystemOne one; private SubSystemTwo two; public Facade() { one new SubSystemOne(); two new SubSystemTwo(); } public void methodA() { one.methodOne(); two.methodTwo(); } }外观模式的关键是 Facade 不增加新功能只做委托和组合。如果 Facade 里出现了业务判断逻辑说明职责越界了。适配器模式解决接口不兼容问题文档里的适配器模式通过继承或组合把 Adaptee 的接口转换成 Target 接口。组合模式处理树形结构文档里的组合模式让叶子节点和容器节点实现同一接口客户端可以一致地处理单个对象和组合对象。这三种结构型模式的共同点是都在做解耦但方向不同外观是简化对外接口适配器是转换接口组合是统一接口。选型时先判断问题是接口太多、接口不匹配还是结构是树形再对应选择。3.3 单例与中介者全局唯一与多对多解耦单例模式保证一个类只有一个实例。文档里的单例模式基础实现是私有构造函数加静态方法返回唯一实例。多线程环境下需要加锁或使用静态内部类。public class Singleton { private static Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if (instance null) { instance new Singleton(); } return instance; } }参数说明synchronized 保证线程安全但每次调用都加锁影响性能。更常用的做法是双重检查锁定或静态内部类。单例的坑在于如果单例持有可变状态测试时很难隔离如果单例初始化依赖外部资源启动顺序不好控制。我一般只在配置管理、连接池、日志器这类确实需要全局唯一的场景用单例。中介者模式解决同事类之间多对多通信问题。文档里的中介者模式让每个同事类持有 Mediator 引用通信时通过中介者转发而不是直接调用其他同事类。// 抽象中介者 public abstract class Mediator { public abstract void send(String message, Colleague colleague); } // 抽象同事类 public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator mediator; } } // 具体同事类 public class ConcreteColleagueA extends Colleague { public ConcreteColleagueA(Mediator mediator) { super(mediator); } public void send(String message) { mediator.send(message, this); } public void notify(String message) { System.out.println(同事A收到消息 message); } }中介者的代价是中介者本身可能变得复杂。如果同事类数量多、交互逻辑复杂中介者会膨胀成上帝类。通常的做法是交互规则简单时用中介者规则复杂时考虑拆成多个中介者或改用事件总线。4. 模式对比与选型15 种剩余模式的归类方法4.1 创建型模式对比简单工厂、工厂方法与抽象工厂文档里给出了创建型模式的对比维度。简单工厂是一个工厂类根据参数创建不同产品工厂方法是每个产品对应一个工厂类抽象工厂是一个工厂类创建一组产品族。对比项简单工厂工厂方法抽象工厂产品数量单一产品单一产品产品族扩展方式改工厂类加工厂类加工厂类是否违反开放-封闭是否增加产品族时是适用场景产品少且稳定产品扩展频繁多产品族切换选型逻辑如果产品种类少且不常变简单工厂够用如果产品种类会持续增加用工厂方法如果需要整体切换产品族比如从 SqlServer 切到 Access用抽象工厂。建造者模式关注的是分步构建复杂对象和工厂模式的区别在于工厂返回产品建造者返回构建过程。4.2 结构型与行为型模式对比易混淆模式辨析文档里列出了几组容易混淆的模式。适配器、装饰器、代理模式都涉及包装对象但意图不同适配器改变接口装饰器增强功能代理控制访问。组合模式和装饰器模式都涉及递归组合但组合模式处理树形结构装饰器模式处理功能叠加。行为型模式里策略模式和状态模式结构相似但策略模式由客户端选择算法状态模式由对象状态自动切换行为。观察者模式和中介者模式都涉及对象间通信观察者是一对多通知中介者是集中式转发。责任链模式和中介者模式都解耦了发送者和接收者责任链是链式传递中介者是星型转发。4.3 模式选择的关键维度文档最后总结了模式选择的关键维度。我一般按四个问题来筛第一变化点在哪里是对象创建、接口不兼容、算法切换还是状态转换第二变化频率如何频繁变化用模式封装稳定不变直接写第三类数量是否可控模式会增加类数量小项目过度使用会降低可读性第四团队是否熟悉该模式不熟悉的模式会增加沟通成本。这四个问题回答完模式基本就确定了。如果两个模式都符合选类数量少、团队更熟悉的那个。模式是手段不是目的代码可维护性才是目标。5. 避坑与常见问题模式使用中最容易翻车的五个点5.1 抽象工厂新增产品类型导致全量修改现象项目初期用抽象工厂管理数据库访问后来要新增一个登录日志产品发现要改 IFactory 接口、SqlServerFactory、AccessFactory 以及所有相关类。原因抽象工厂的接口是按产品族设计的新增产品类型意味着所有具体工厂都要实现新方法这违反了开放-封闭原则。解决如果产品类型会持续增加不要用抽象工厂改用工厂方法或简单工厂加配置。如果只是偶尔新增接受这次修改但要在设计文档里记录这个取舍。5.2 策略模式与简单工厂混用导致 Context 职责过重现象CashContext 构造函数里根据字符串创建具体策略后来策略种类增加到十几种Context 里堆满了 if-else。原因策略模式负责算法切换简单工厂负责对象创建两者混在一个类里Context 同时承担了创建和使用职责。解决把创建逻辑抽到独立的工厂类Context 只接收策略对象。如果客户端需要根据配置选择策略可以在工厂类里做映射Context 保持单一职责。5.3 单例模式在测试中无法隔离现象单元测试时前一个测试修改了单例的状态后一个测试读到脏数据测试结果不稳定。原因单例的生命周期和进程一致测试之间共享同一个实例。解决单例类提供 reset 方法用于测试或者用依赖注入替代单例把全局实例改为可注入的普通对象。如果必须用单例测试时通过反射重置静态字段。5.4 中介者膨胀为上帝类现象中介者模式用了一段时间后Mediator 类里出现了大量条件判断和业务逻辑修改一个同事类的交互规则要改中介者。原因所有同事类的通信都经过中介者交互规则复杂时中介者自然膨胀。解决按业务域拆分多个中介者或者引入事件机制替代直接转发。中介者只负责路由不负责业务判断。5.5 过度使用模式导致类数量爆炸现象一个小模块用了五六个模式类文件几十个新人接手时找不到入口。原因为了用模式而用模式忽略了项目规模和团队熟悉度。解决小项目优先用简单工厂和策略结构型模式按需引入。每引入一个模式问自己不用这个模式代码会差在哪里如果答案不明确就不引入。6. 验收与答辩怎么证明你的模式选型是对的验收设计模式方案不是看用了多少种模式而是看变化点是否被封装、客户端是否依赖抽象、新增功能是否只加类不改原有代码。我一般用三个检查动作来验收。第一个动作画变化点映射表。把需求里所有可能变化的点列出来每个变化点对应一个模式或一个设计决策。比如折扣算法变化对应策略模式数据库类型变化对应抽象工厂界面调用简化对应外观模式。答辩时这张表能直接说明每个模式的存在理由。第二个动作做扩展演练。假设要新增一种折扣、新增一个数据库、新增一个子系统方法看需要改哪些文件。如果只加新类不改原有类开放-封闭就做到了。如果必须改接口或工厂类说明这个方向的扩展是有代价的要能解释为什么接受这个代价。第三个动作检查客户端代码。客户端里不应该出现具体产品类名、具体策略类名、具体子系统类名。如果出现了依赖倒转就没做到。客户端只应该依赖抽象接口和上下文类。验收项合格标准检查方式变化点封装每个变化点有对应模式或设计决策变化点映射表开放-封闭新增功能只加类不改原有类扩展演练依赖倒转客户端不出现具体类名代码扫描单一职责每个类只有一个变化原因类职责清单模式数量合理每个模式都有明确的存在理由模式理由表答辩时还有一个技巧准备一个反例。说明如果不用这个模式代码会变成什么样。比如不用策略模式acceptCash 里会有大量 if-else不用抽象工厂客户端会直接 new SqlserverUser。反例比正例更能说明模式的价值。模拟试卷里的题也值得过一遍。文档提供了题和卷子做题时不要只记答案要回到模式定义和 UML 类图去验证。选择题考的是模式分类和适用场景简答题考的是模式对比和原则应用。把错题对应的模式重新画一遍类图比背答案有效。从那以后我每次做模式选型都强制走一遍变化点映射和扩展演练确认每个模式都有不可替代的理由才写进方案。希望帮到你。本文还有配套的精品资源点击获取