这里的创建型模式指,以下的设计模式关注的是创建新对象的过程。工厂与抽象工厂,通过引入一个额外的工厂对象,以解耦对象创建逻辑与创建调用的逻辑;建造器模式是在工厂模式的基础上提出,将对象创建的过程细化为线性的步骤,以此满足一些复杂对象的创建需求(这真的有必要定义成独立一个模式嘛);原型设计模式提出将创建流程变为复制现有对象,以此来简化流程;单例模式则是常用的了,就是通过创建一个全局对象来更便捷地处理一些全局操作。
注意 此章学习下来确实感觉到这些个设计模式其实是不必过分纠结于各个具体的定义与所谓“标准实现”的,我感觉更应该关注设计模式背后希望解决避免的开发问题,及其解决问题的思路。(倘若陷入到盲目背诵,感觉就像是纠结“茴”字有几种写法了。)
工厂方法模式
要素:
- 抽象产品:定义一个通用的产品基类
- 具体产品:继承自抽象产品,包含对于通用接口的不同实现
- 抽象工厂:声明一个用于创建产品的通用接口
- 具体工程:继承自抽象工厂,负责实例化具体的产品对象并返回
核心目的:
- 遵循开闭原则与单一职责原则
- 解耦具体产品创建代码与使用产品的客户端代码
- 封装对象创建逻辑,提高可读性
优:
- 更好的可扩展性
- 添加新的产品
- 创建产品组合
- 更好的可维护性
- 便于单独修改产品创建逻辑/调用创建逻辑
劣:
- 对于简单系统/对象,有过度设计的嫌疑
- 过多工厂类可能掩盖对象的创建逻辑
- 单独的工厂方法模式,不便处理存在组合关系的产品
应用示例
- 日志系统:要求多种不同的输出形式
- 数据库驱动:要求连接多种不同数据库
- 文档导出:要求多种不同文档格式
抽象工厂模式
可以视作对于单一维度的工厂模式的拓展,要素目的应用都比较相似。使用的先决条件是对象的抽象概念是成组的,也因此应用场景相对窄。
其实可以视作通过提升耦合的层级(从单一产品到一套产品簇),牺牲创建粒度,提升创建的一致性,并因此提供可整体切换的便利性。
建造者模式(生成器模式)
与工厂模式的出发点有共同之处,都是希望通过一个额外的对象来代理创建目标对象的过程,以此解耦逻辑。而建造者模式的额外重点在于使用一套更细粒度创建逻辑。
要素:
- 产品:定义了需要创建的产品数据结构,此为生成时逐步构建的对象
- 抽象生成器: 声明了创建一个产品生成器需要的实现的多个步骤的接口
- 具体生成器: 实现了创建一个产品的各个步骤的具体逻辑
- 导演/主管: 代理创建一个产品的各个步骤,也就是调用具体生成器中的方法,以创建产品
优:
- 拆分类构造逻辑,避免构造函数臃肿
- 构造步骤可灵活组合排序
- 各个构造步骤可按需求定制调整
应用示例
- HTTP请求的构造与发起
原型设计模式
就是将“创建新对象”的行为变为“复制现有对象的原型”,以此来简化创建新对象的流程。
要素:
- 原型接口(抽象类):声明统一的克隆接口
- 具体的原型对象:实现了自身的构造逻辑,克隆接口中直接返回使用拷贝自身构造的对象
优:
- 动态多态,实现了拷贝接口的对象都可以调用方法
- 拷贝范围可控,避免拷贝多余的局部对象状态
应用示例
- 游戏引擎的预制体/场景实例化
单例模式
就是指创建一个存活于整个项目生命周期的对象,使用它来处理一些全局的操作。可以根据初始化策略分为“饿汉式”与“懒汉式”。
要素:
- 一个单例模式类
- 提供对外的访问方法
- 可以包括对于赋值、拷贝构造的禁用
- 照类模板抄就行
优:
- 使用一个贯穿整个生命周期的全局对象进行某些操作,概念上直白易懂,符合面向对象的直觉设计
劣:
- 引入全局状态
- 破坏单一职责原则
- 单例类同时承担了实例化与具体的业务逻辑
- 多个单例对象可能需要彼此交互,造成依赖关系
- 使得初始化顺序变得模糊
- 调用逻辑杂糅不便于维护
- 单例模式泛用给人的感觉就像是某种逃避设计“将不必要功能方法封装为单例对象,并将调用逻辑散落在项目各处”,这在直观感受上就是比较危险的