创建型模式提供了创建对象的机制, 旨在提升已有代码的灵活性、可复用性、可扩展性
单例模式
Singleton
问题
- 唯一实例
-
优点
减少内存分配
-
缺点
违背单一职责原则,一个类应该关心其内部功能,不应该关心外部如何初始化自身
应用场景
饿汉模式,多见于游戏开发,加载程序后一次性初始化所有对象,后续不会再有内存分配
懒汉模式,模块化场景,不同模块在不同客户环境必要性不同,减少内存分配,需要注意并发安全
与其他设计模式的关系
-
简单工厂
非设计模式,又叫静态工厂方法,Static Factory Method
问题
需要经常创建不同风格的椅子,存在大量下列代码,有什么问题?
auto chair1 = new ArtDecoChair()
auto chair2 = new VictorianChair()
auto chair3 = new ModernChair()
调用者不必关心对象创建和组织细节,从直接创建具体产品对象的尴尬局面摆脱出来,明确了职责
缺点
工厂类集中了所有实例的创建逻辑,违反了高内聚的责任分配原则,扩展时需要修改工厂类
-
应用场景
只在很简单的情况下应用,比如:
-
工厂方法模式
Factory Method,Virtual Constructor
问题
方案
- 抽象产品
工厂返回创建产品的工厂方法,该方法返回的对象与抽象产品接口相匹配
意图
是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
结构特征
产品抽象类,申明接口
- 产品具体类,实现接口
- 工厂类申明返回产品对象的工厂方法,返回的对象类型与产品抽象匹配
- 工厂具体类,实现工厂方法
- 可以将工厂方法申明为抽象方法,也可以在基础工厂方法返回默认产品类型
- 工厂方法不一定每次会新建对象,可以返回缓存、对象池或其他来源的已有对象
优点
- 避免创建者与产品耦合
- 单一职责,创建逻辑独立
-
缺点
-
应用场景
编写代码的过程中, 如果无法预知对象确切类别及其依赖关系时
- 如果你希望用户能扩展你软件库或框架的内部组件
如果你希望复用现有对象来节省系统资源, 而不是每次都重新创建对象
与其他设计模式的关系
项目初期大都会使用工厂模式,后期可能会演化为抽象工厂方法模式,原型模式和生成器模式
抽象工厂模式
Abstract Factory
问题
优点
问题
对象构造时参数过多,并非所有参数需要,比如下列示例如何优化?
class House {
public:
House(
int windows,
int doors,
int rooms,
bool hasGarden,
bool hasSwimPool,
bool hasGarage
){
cout << "A new house!" << endl;
}
};
方案
- 定义通用步骤,基本生成器中申明这些步骤
- 实现具体生成器
-
意图
分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。
结构特征
生成器抽象
- 具体生成器
- 最终产品
- 主管类(可选)
- 主管类与某个生成器关联
优点
- 可以分步创建对象, 暂缓创建步骤或递归运行创建步骤
- 生成不同形式的产品时, 你可以复用相同的制造代码
单一职责原则。 你可以将复杂构造代码从产品的业务逻辑中分离出来
缺点
-
应用场景
避免大量构造函数
class Pizza { Pizza(int size) { ... } Pizza(int size, boolean cheese) { ... } Pizza(int size, boolean cheese, boolean pepperoni) { ... } // ...
需要创建不同形式的产品
- 对象创建复杂,但可以分解成多个独立步骤
可以优化,链式调用
原型模式
Clone,ProtoType
问题
如果你有一个对象, 并希望生成与其完全相同的一个复制品, 你该如何实现呢?
有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的,这是又该如何实现?
方案
意图
结构特征
- 可以克隆对象, 而无需与它们所属的具体类相耦合
- 避免反复运行初始化代码
-
缺点
-
应用场景
如果你需要复制一些对象, 同时又希望代码独立于这些对象所属的具体类(这一点考量通常出现在代码需要处理第三方代码通过接口传递过来的对象时)
- 可以使用一系列预生成的、 各种类型的对象作为原型直接克隆,有时候克隆成本远小于构造
示例
builder.cpp
factory_v1.cpp
factory_v2.cpp
factory_v3.cpp
main.cpp