前言
本文来总结回顾一下之前学习的 26 中设计模式。
在正文开始之前,先抛出一个问题:我们为什么要学习设计模式?
GoF 的设计模式是 Java 基础知识和 J2EE 框架知识之间一座隐性的"桥"
设计模式和 J2EE 在思想和动机上是一脉相承的,我总结了以下几个原因:
- 设计模式更抽象。 J2EE 是具体的产品代码,我们在日常工作中就可以接触到,而设计模式在对每个应用时才会产生具体代码;
- 设计模式是比 J2EE 等框架软件更小的体系结构, J2EE 中许多具体程序都是应用设计模式实现的。当你深入到 J2EE 的内部代码研究时,这点尤其明显。因此,如果不具备设计模式的基础知识,你可能很难理解 J2EE 的代码,从而难以灵活应用 J2EE 框架;
- J2EE 只是适合企业计算应用的框架软件,但是 GoF 的设计模式几乎可以用于任何应用。因此 GoF 的设计模式是 J2EE 的重要理论基础之一。
所以说,GoF 的设计模式是 Java 基础知识和 J2EE 框架知识之间一座隐性的" 桥" 。
七大设计原则总结
设计原则 | 总结归纳 | 主要目的 |
---|---|---|
开闭原则 (Open-Close) | 对扩展开放,对修改关闭 | 减少维护带来新的风险 |
依赖倒置原则 (Dependence Inversion) | 高层模块不应依赖低层 | 更利于代码结构的升级扩展 |
单一职责原则 (Simple Responsibility) | 一个类只干一件事 | 便于理解,提高代码可读性 |
接口隔离原则 (Interface Segregation) | 一个接口只干一件事 | 减小功能解耦,高聚合、低耦合 |
迪米特法则 (Law of Demeter) | 不该知道的不要知道 | 只和朋友交流,不和陌生人说话,减少代码冗余 |
里氏替换原则 (Liskov Substitution) | 子类重写方法功能发生改变,不应该影响父类方法的含义 | 防止继承泛滥 |
合成复用原则 (Composite/Aggregate Reuse) | 尽量使用组合实现代码复用,而不使用继承 | 降低代码耦合 |
设计模式是前人经验的总结,形成方法论供后人借鉴使用。设计模式是在我们迷茫时提供的一种解决问题的方法论,或者说用好设计模式可以对一些问题防范于未然。
设计模式也是一门艺术。艺术来源于生活,而设计模式则来源于解决实际的代码问题的经验总结,我们不要为了套用设计模式而去使用设计模式。
GOF 23 设计模式
分类回顾
GOF 23 种设计模式简单分类如下:
- 创建型:工厂方法模式 (Factory Method) 、抽象工厂模式 (Abstract Factory) 、单例模式 (Singleton) 、原型模式 (Prototype) 、建造者模式 (Builder)
- 结构型:代理模式 (Proxy) 、门面模式 (Facade) 、装饰器模式 (Decorator) 、享元模式 (Flyweight) 、组合模式 (Composite) 、适配器模式 (Adapter) 、桥接模式 (Bridge)
- 行为型:模板方法模式 (Template Method) 、策略模式 (Strategy) 、责任链模式 (Chain of Responsibility) 、迭代器模式 (Iterator) 、命令模式 (Command) 、状态模式 (State) 、备忘录模式 (Memento) 、中介者模式 (Mediator) 、解释器模式 (Interpreter) 、观察者模式 (Observer) 、访问者模式 (Visitor)
相互依赖关系如下:

从经验来看,以上设计模式的使用(可能需要自己造轮子)频率大致分布如下:
设计模式类型 | 高频使用 | 低频使用 |
---|---|---|
创建型模式 (Creational) | 厂方法模式 (Factory Method) 、抽象工厂模式 (Abstract Factory) 、单例模式 (Singleton) 、 建造者模式 (Builder ) | 原型模式 (Prototype) |
结构型模式 (Structural) | 代理模式 (Proxy) 、门面模式 (Facade) 、装饰器模式 (Decorator) 、享元模式 (Flyweight) 、适配器模式 (Adapter) 、组合模式 (Composite) | 桥接模式 (Bridge) |
行为型模式 (Behavioral) | 模板方法模式 (Template Method) 、策略模式 (Strategy) 、责任链模式 (Chain of Responsibility) 、状态模式 (State) | 备忘录模式 (Memento) 、观察者模式 (Observer) 、迭代器模式 (Iterator) 、中介者模式 (Mediator) 、命令模式 (Command) 、解释器模式 (Interpreter) 、访问者模式 (Visitor) |
思想总结
创建型模式
设计模式 | 一句话归纳 | 目的 | 现实案例 | 典型应用案例 |
---|---|---|---|---|
工厂模式 (Factory) | 产品标准化,生产更高效 | 封装对象创建的细节 | 实体工厂 | LoggerFactory 、 Calender |
单例模式 (Singleton) | 世上只有一个你 | 保证对象独一无二 | 公司 CEO | BeanFactory 、 Runtime |
原型模式 (Prototype) | 拔一根猴毛,吹出千万个 | 高效创建对象 | 克隆技术 | ArrayList 、 PrototypeBean |
建造者模式 (Builder) | 高配中配低配,任你挑选 | 开放个性配置步骤 | DIY 组装 | StringBuilder 、 BeanDefinitionBuilder |
结构型模式
设计模式 | 一句话归纳 | 目的 | 现实案例 | 典型应用案例 |
---|---|---|---|---|
代理模式 (Proxy) | 没有资源没时间,得找中介来帮忙 | 对象职责增强 | 房产中介,婚恋中介 | ProxyFactoryBean 、 JdkDynamicAopProxy 、 CglibAopProxy |
门面模式 (Facade) | 打开一扇门,走向全世界 | 提供统一的子系统的访问入口 | 公司前台,导医台 | JdbcUtils 、 RequestFacade |
装饰器模式 (Decorator) | 奶油蛋糕巧克力蛋糕,都是蛋糕 | 基于继承体系的灵活扩展 | 煎饼、蛋糕 | BufferedReader 、 InputStream |
享元模式 (Flyweight) | 优化资源配置,减少重复浪费 | 共享资源池 | 全国社保联网 | String 、 Integer 、 ObjectPool |
组合模式 (Composite) | 一条绳子上的蚂蚱 | 统一(有相关性的)整体和个体 | 组织架构树 | HashMap 、 SqlNode |
适配器模式 (Adapter) | 老系统新需求,亡羊补牢 patch 来凑 | 使相关功能适配新的接口需求 | 电源适配器 | AdvisorAdapter 、 HandlerAdapter |
桥接模式 (Bridge) | 约定优于配置 | 不使用继承,耦合多个不同维度的对象 | 小桥 | DriverManager |
行为型模式
设计模式 | 一句话归纳 | 目的 | 现实案例 | 典型应用案例 |
---|---|---|---|---|
委派模式 (Delegate) | 这个需求很简单,怎么实现我不管 | 只对结果负责 | 授权委托书 | ClassLoader 、 BeanDefinitionParserDelegate |
模板模式 (Template) | 流程全部标准化,细节操作你行你上 | 逻辑复用,统一封装 | 把大象装进冰箱分几步 | JdbcTemplate 、 HttpServlet |
策略模式 (Strategy) | 条条大道通北京,具体哪条你来定 | 把选择权交给用户 | 选择支付方式 | Comparator 、 InstantiationStrategy |
责任链模式 (Chain of Responsibility) | 各人自扫门前雪,莫管他人瓦上霜 | 解耦链式逻辑 | 报销签字流程 | FilterChain 、 Pipeline |
迭代器模式 (Iterator) | 流水线上坐一天,每个包裹扫一遍 | 统一的集合对象访问方式 | 物流分拣出库 | Iterator |
命令模式 (Command) | 运筹帷幄之中,决胜千里之外 | 解耦请求和处理逻辑 | 遥控器 | Runnable 、 TestCase |
状态模式 (State) | 状态驱动行为,行为决定状态 | 状态和行为绑定 | 订单状态处理 | Lifecycle |
备忘录 (Memento) | 给我一剂 “后悔药” | 状态备份 | 草稿箱 | StateManageableMessageContext |
中介者 (Mediator) | 联系方式我给你,怎么搞定靠自己 | 统一平级网状资源的管理 | 朋友圈 | Timer |
解释器模式 (Interpreter) | 方言翻译家 | 实现特定语法解析 | 摩斯密码、数学表达式 | Pattern 、 ExpressionParser |
观察者模式 (Observer) | 到点就通知我 | 解耦观察者与被观察者 | 闹钟 | ContextLoaderListener |
访问者模式 (Visitor) | 横看成岭侧成峰,远近高低各不同 | 解耦数据结构和数据操作 | 不同人员不同的 KPI 考核指标 | FileVisitor 、 BeanDefinitionVisitor |
设计模式的联系和对比
- 单例模式和工厂模式
- 实际业务代码中,通常会把工厂类设计为单例。
- 策略模式和工厂模式
- 工厂模式包含工厂方法模式和抽象工厂模式,是创建型模式;策略模式属于行为型模式。
- 工厂模式主要目的是封装好创建逻辑,策略模式接收工厂创建好的对象,从而实现不同的行为。
- 策略模式和委派模式
- 策略模式是委派模式内部的一种实现形式,策略模式关注的是结果是否是能相互代替的。
- 委派模式更关注任务分发和调度的过程。
- 模板方法模式和工厂方法模式
- 工厂方法是模板方法的一种特殊实现。相当于只有一个步骤的模板方法模式,这一个步骤交给子类去实现;而模板方法模式包含多个步骤交给子类实现,顺序不可变更替换。
- 模板方法模式和策略模式
- 模板方法和策略模式都有封装算法。
- 策略模式是使不同算法可以相互替换,且不影响客户端应用层的使用。
- 模板方法是针对定义一个算法的流程,将一些有细微差异的部分交给子类实现。
- 模板方法模式不能改变算法流程,策略模式可以改变算法流程且可替换。策略模式通常用来代替
if/else
等条件分支语句。举例:策略模式中不同的支付方式可以相互替代,模板类 JdbcTemplate 中的步骤缺一不可且顺序不可改变。
- 装饰者模式和静态代理模式
- 装饰者模式关注点在于给对象动态添加方法;而代理更加注重控制对对象的访问。
- 代理模式通常会在代理类中创建被代理对象的实例,而装饰者模式通常把被装饰者作为构造参数。
- 装饰者和代理者虽然都持有被增强的对象的引用,但关注的重心是不一样的。
- 装饰者模式和适配器模式
- 装饰者模式和适配器模式都是属于包装器模式 (Wrapper Pattern) 。
- 装饰者模式可以实现被装饰者与相同的接口或者继承被装饰者作为它的子类,而适配器和被适配者可以实现不同的接口。
- 适配器模式和静态代理模式
- 适配器可以结合静态代理来实现,保存被适配对象的引用,但不是唯一的实现方式。
- 适配器模式和策略模式
- 在适配业务复杂的情况下,利用策略模式优化动态适配逻辑。
- 代理模式和中介者模式
- 代理模式:职责增强,不仅要建立联系,还要参与过程;
- 中介模式:只负责牵线搭桥,建立联系。
- 委派模式和代理模式
- 委派模式:是一种全权的静态代理,不做任何的增强;
- 代理模式:一定会有增强。没有任何功能增强的代理就是委派。
- 命令模式和策略模式
- 命令模式:解耦请求和处理,会有一个回调,会有反馈和处理结果
- 策略模式:对于固定好的选项,一定是同样的结果
- 都是为客户端提供一个策略/命令清单
- 代理模式和装饰器模式
- 代理模式:组合实现功能增强和扩展
- 装饰器模式:继承实现增强和扩展
- 委派模式和责任链模式
- 委派模式:没有流程的概念,只需要拿到结果;
- 责任链模式:处理流程,处理流程可扩展,可定制,最终结果由责任链中的某些 Handler 来决定。
- 工厂方法与抽象工厂
- 工厂方法:产品扩展,单向维度;
- 抽象工厂:产品等级结构和产品族的相互扩展关系,多维度,至少是二维。
- 桥接模式与适配器模式
- 桥接模式:不使用继承建立联系;
- 适配器:类适配器用的继承、对象适配器用的是组合、接口适配器实际上也是继承。
- 行为型模式、结构型模式、创建型模式
- 行为型:对 Java 中的方法使用提出的建议
- 结构型:对 Java 类的组合方式提出建议
- 创建型:对创建 Java 对象的形式提出的建议
- 抽象工厂方法与模板方法
- 抽象工厂:形式上可能会出现抽象方法,但是并不能体现流程;
- 模板方法:也是有可能出现抽象方法,但是一定是某个流程中的一个步骤。
- 建造者模式 vs 装饰器模式
- 建造者模式:强调对象创建步骤的个性化,一般来说会有标配对象;
- 装饰器模式:更加强调扩展性,大桶套小桶。
- 适配器模式 Vs 中介者模式
- 适配器模式:解决接口兼容问题,可以用继承,也可以用组合
- 中介者模式:一定是用组合,所有人可能都持有中介者引用
- 桥接模式与中介者模式
- 共同点:不用继承,一定是用组合
- 桥接模式:两个维度建立连接
- 中介者模式:多维度建立连接(是一个更复杂的桥接模式的实现)
- 桥接模式与组合模式
- 桥接模式:两个继承体系建立连接,反而就是为了满足个性的
- 组合模式: 目的不是为了建立连接,而是为了统一行动,统一一套 API
- 门面模式与装饰器模式
- 门面模式:为多个子系统提供统一的入口,承担一定的静态代理作用
- 装饰器模式:目的是为了扩展,一定是在一个继承体系中的
- 门面模式与委派模式
- 在门面模式中,可能会用到委派模式实现任务分发
- 享元模式与饿汉式单例
- 我们可以把对象池的容器设置的单例;同时,把对象池所在类设置为单例的工厂。
- 桥接模式与命令模式
- 桥接模式:需要一个中间的类,一定有功能实现的
- 命令模式:需要一个抽象的中间类,只是为了规范(没有也可以,只是为了解耦命令)
- 适配器模式与策略模式
- 适配器模式:目的是接口的兼容
- 策略模式:策略的选择权交给用户
- 策略模式与模板模式
- 有时候会混用,模板模式中的钩子方法,就是某一个策略的实现
文章评论