设计模式介绍
文章目录
创建型
创建型模式提供了创建对象的机制,能够提升已有代码的灵活性和可复用性。
框架给用户提供扩展能力:
- 工厂方法。框架中使用工厂接口创建实例,客户端可以定义并传入自己的具体工厂类。
- 抽象工厂
对象复用:
- 单例
- 工厂方法等
创建对象的步骤复杂时:
- 建造者
对象复制代替创建:
- 原型
名称 | 特点 | 原则 | 缺点 | 场景 | 结构图 |
---|---|---|---|---|---|
抽象工厂 | 工厂接口提供创建一系列抽象产品的方法; 按照实现方式的不同,若干具体工厂提供创建这一系列产品的方法 |
单一职责将一系列产品的创建逻辑抽取到同一个工厂类; 开闭,方便增加新产品和工厂 |
代码复杂 | 同种产品分为不同的系列,形成矩阵(产品种类维度/系列维度) | ![]() |
工厂方法 | 工厂接口提供创建某种抽象产品的方法; 若干具体工厂提供创建相应具体产品的方法; |
开闭,增加产品和工厂很方便; 单一职责,产品的创建和使用逻辑分离 |
引入子类代码变复杂 | 暂时不知道如何创建对象时,分离对象的创建和使用逻辑; 作为框架,支持客户端扩展产品类别时 |
![]() |
简单工厂 | 没有工厂接口,只有一个创建方法根据参数返回具体产品接口对象 | - | 不满足开闭,增加产品需要在创建方法中新增新产品的创建逻辑 | 已知不会增加新的产品,后期不会修改产品创建方法时 | ![]() |
建造者 | Builder接口抽象对象的创建步骤; 具体Builder类实现接口并提供获取最终对象的方法; Director类持有Builder接口引用并调度创建方法的执行,向客户端屏蔽复杂的创建步骤; 客户端通过Director调度Builder,通过Builder.getResult方法获取最终对象 |
单一职责,分离对象的创建逻辑 创建代码可复用 |
代码复杂 | 构造参数众多; 使用类似代码创建不同产品; 分步创建对象; 可以延迟或递归执行; |
![]() |
单例 | 私有构造函数,提供获取单例对象的方法; 懒汉饿汉 |
- | 懒汉模式多线程写同一对象问题 | 资源类/配置类对象 | ![]() |
原型 | 类提供Clone方法实现对象的自身复制,而不是让外部实现复制功能 | 方便生成复杂对象 | 克隆包含循环引用的对象会麻烦 | 需要复制对象且不想依赖对象所属的类; 对象创建成本很高 |
![]() |
结构型
结构型模式介绍如何将对象和类组装成较大的结构,并同时保持结构的灵活和高效。
扩展第三方功能:
- 适配器。第三方库参数为目标接口,客户端实现适配器封装本地对象。
工作委派,运行时替换:
- 代理,由代理类负责目标类对象的生命周期管理
- 装饰器,由客户端负责目标类对象的生命周期管理
- 桥接
树状结构:
- 组合
节约内存:
- 享元
封装复杂子系统:
- 外观
名称 | 特点 | 原则 | 缺点 | 场景 | 结构图 |
---|---|---|---|---|---|
代理 | 代理类实现和目标类相同接口,持有目标类对象引用; 代理类负责目标类对象生命周期; 客户端使用代理类对象,代理转发到目标对象 |
开闭,方便增加新代理; 单一职责,目标类仅关注主要业务; 目标对象不存在也不影响代理对象 |
服务响应延迟 | 延迟初始化/生命周期管理/访问控制等 | ![]() |
桥接 | 逻辑上的高层次业务类持有低层次实施类对象,两种类属于不同维度(业务方/实施方); 由客户端组合后,调用高层次类对象 |
组合代替继承; 单一职责,高层抽象和底层实现分离; 开闭,方便新增高层抽象和底层实现,互不影响 |
代码复杂 | 平台无关实现(底层实施层提供多平台实现); 功能组合 |
![]() |
外观 | 持有若干复杂子系统类对象,向客户端提供简单接口 | 分层设计 | 外观类可能成为上帝对象 | 软件分层 | ![]() |
享元 | 将类中不频繁修改的较大内存的内在状态属性放在享元类中,多对象共享享元对象; 结合工厂获取享元对象 |
节约内存 | 牺牲执行速度/引入计算 | 类包含大内存属性 | ![]() |
适配器 | 适配器持有被适配对象引用,实现目标接口,内部实现依赖被适配对象的能力; 提供数据转换能力 |
单一职责,数据转换代码从核心业务中分离; 开闭,使用适配器接口方便引入新适配器 |
复杂度增加 | 扩展不可变类的功能,封装本地对象以实现不可变类需要的目标接口; 数据格式适配 |
![]() |
组合 | 树状文件系统结构,文件和目录类均实现相同接口,使用接口访问这个树状结构,无需了解精确的结构构成 | 多态; 开闭,向结构中添加元素不用修改客户端 |
对差异较大的类抽公共方法较困难 | 树状结构 | ![]() |
装饰器 | 装饰器实现和目标类相同的接口,持有目标类对象引用并调用其方法; 客户端负责构造目标对象和装饰器对象; 客户端使用装饰器对象,对目标对象实现功能增强 |
单一职责,将复杂功能拆分成若干小类; 开闭,支持新的装饰器; 运行时设置对象功能 |
最终行为受装饰顺序影响 | 运行时用非继承的方式增加功能 | ![]() |
行为型
行为模式负责对象间的高效沟通和职责委派。
扩展第三方功能:
- 访问者
链式结构:
- 责任链
- 迭代器
- 备忘录
工作委派,消除if-else:
- 策略,不同策略互不感知
- 状态,状态之间互相了解
消除组件间依赖(耦合):
- 中介者
发布订阅:
- 观察者
去除重复代码:
- 模板方法
动作封装为对象:
- 命令
名称 | 特点 | 原则 | 缺点 | 场景 | 结构图 |
---|---|---|---|---|---|
迭代器 | 持有集合的引用并实现迭代器接口getNext/hasNext; 内部字段维护集合上的迭代状态 |
单一职责,抽离复杂的遍历算法; 开闭,方便引入新的迭代器; 可以暂停遍历/并行遍历 |
某些集合使用迭代器的效率会降低 | 为复杂集合/未知结构提供遍历方法 | ![]() |
策略 | 类持有对策略接口的引用; 类向客户端提供策略设置方法/动作执行方法; 类方法调用策略方法 |
开闭原则,增加策略不用修改主类; 运行时切换策略; 隔离算法的实现和使用; 工作委派 |
客户端必须了解策略的细节来选择合适的策略 | 业务逻辑需要动态切换实现算法时; 配合工厂模式获取策略消除if-else |
![]() |
观察者 | 发布者维护订阅者列表,向客户端提供订阅/取消订阅/触发通知方法; 订阅者实现通知接口给发布者调用 |
开闭原则,无需修改发布者就能增加新的订阅者; 运行时建立对象之间的联系 |
订阅者的通知顺序随机 | 对象变化后需要通知其它对象; 需要观察其他对象 |
![]() |
状态 | 类持有对状态接口handler的引用state; 类handler调用state.handler; 类提供状态切换方法chg; 状态类实现接口handler并持有状态类引用,适当时调用chg切换状态 |
单一职责,状态相关代码放在状态类; 开闭,方便引入新状态; 消除if-else; 工作委派 |
不适合状态较少时使用 | 根据自身状态实现不同行为 | ![]() |
命令 | 命令类组合被控对象及参数,提供exec方法调用被控对象; 触发类组合命令对象,提供设置命令/触发命令的方法; 客户端组合命令/被控/触发对象,调用触发对象的触发方法 |
单一职责,解耦触发和执行类; 开闭,方便扩展新命令 |
触发者和被控者之间新增层次,代码复杂 | 队列发送命令/命令历史/运行时切换命令/动作转为对象/多命令组合; 延迟/重复执行 |
![]() |
中介者 | 中介者持有其他组件对象的引用; 其它组件对象互不感知,持有中介者接口引用; 组件对象方法调用中介者接口(传递自身),中介者再调用其他组件对象方法 |
单一职责,多组件的交流抽取到中介者维护; 开闭,无需修改组件就能增加中介者; 去除组件耦合 |
中介者变为上帝对象 | 消除组件间复杂依赖 | ![]() |
责任链 | 类实现setNext/handle接口并持有next引用; 本对象handle结束后自行决定是否调用next.handle; 客户端将对象串成链 |
开闭原则方便新增处理者; 方便控制请求顺序; 解耦发起方和执行方 |
有请求最终可能都未被处理 | 按顺序执行多个处理者时 | ![]() |
备忘录 | 备忘录类包含原类引用及快照字段,提供restore调用原类set方法; 原类提供生成备忘录和根据快照状态恢复的set方法; 负责人类维护备忘录列表,提供undo调用备忘录restore方法 |
单一职责,负责人提供维护历史状态功能,简化原类代码 | 消耗内存; 负责人需要跟踪对象生命周期以回收内存 |
需要快照和回滚 | ![]() |
模板 | 父类持有子类接口的引用并实现一个模板方法和若干子方法的默认实现; 子类组合父类并实现接口的若干子方法; 客户端实例化并调用父类模板方法 |
消除重复模板代码 | 部分客户端受到模板方法逻辑限制 | 只希望客户端扩展算法的某个步骤而不是整个算法时; 多个算法流程类似时 |
![]() |
访问者 | 不同元素类实现accept接口对访问者开放访问入口,入参为访问者接口,各自调用访问者针对自己提供的访问方法; 访问者类针对不同元素类提供不同访问方法,入参为元素对象,将结果保存在自己的字段中 |
开闭,不修改元素类通过新增访问者类向元素类提供新能力; 单一职责,将同一行为的不同版本放在同一个类中 |
新增/删除元素类需要修改所有访问者; 访问者没有元素私有变量的访问权限 |
为第三方不可修改类扩展功能; 访问含有多种对象的层次结构 |
![]() |