10.5.2 创建型设计模式
创建型模式解决“对象如何创建”的问题。它们把创建逻辑从使用者手里拿出来,使客户程序不必依赖具体类,也不必了解复杂构造细节。
创建型共有 5 种:抽象工厂、工厂方法、建造者、原型、单例。
总览表
| 中文名 | 英文名 | 一句话意图 | 题干关键词 |
|---|---|---|---|
| 抽象工厂 | Abstract Factory | 创建一系列相关或相互依赖的对象,不指定具体类 | 产品族、一系列相关产品、联合使用 |
| 工厂方法 | Factory Method | 定义创建对象接口,让子类决定实例化哪个类 | 子类决定、延迟实例化、一个产品 |
| 建造者/生成器 | Builder | 将复杂对象的构建过程与表示分离 | 复杂对象、分步骤构建、同样过程不同表示 |
| 原型 | Prototype | 通过复制已有原型对象创建新对象 | 克隆、复制、减少实例化开销 |
| 单例 | Singleton | 保证一个类只有一个实例,并提供全局访问点 | 唯一实例、全局访问点 |
抽象工厂:生产一族相关产品
抽象工厂提供一个接口,用来创建一系列相关或相互依赖的对象,而不需要指定具体类。
适合场景:系统要支持多个产品系列,并且同一系列产品需要一起使用。例如数据库访问层中,不同数据库都有连接、命令、结果集等一组对象。选择 Oracle 系列时,应创建 OracleConnection、OracleCommand;选择 MySQL 系列时,应创建 MySQLConnection、MySQLCommand。
classDiagram
class AbstractFactory {
+createProductA()
+createProductB()
}
class Factory1
class Factory2
class ProductA
class ProductB
class ProductA1
class ProductA2
class ProductB1
class ProductB2
AbstractFactory <|.. Factory1
AbstractFactory <|.. Factory2
ProductA <|.. ProductA1
ProductA <|.. ProductA2
ProductB <|.. ProductB1
ProductB <|.. ProductB2
Factory1 ..> ProductA1
Factory1 ..> ProductB1
Factory2 ..> ProductA2
Factory2 ..> ProductB2与工厂方法相比,抽象工厂强调“产品族”,不是只生产一个产品。
工厂方法:把实例化推迟到子类
工厂方法定义一个创建对象的接口,但由具体子类决定实例化哪个类。它的关键句是:让子类决定实例化哪个类,将实例化推迟到子类。
classDiagram
class Creator {
+factoryMethod()
}
class ConcreteCreatorA
class ConcreteCreatorB
class Product
class ConcreteProductA
class ConcreteProductB
Creator <|-- ConcreteCreatorA
Creator <|-- ConcreteCreatorB
Product <|.. ConcreteProductA
Product <|.. ConcreteProductB
ConcreteCreatorA ..> ConcreteProductA
ConcreteCreatorB ..> ConcreteProductB考试区分点:
| 对比项 | 工厂方法 | 抽象工厂 |
|---|---|---|
| 创建对象数量 | 通常返回一个产品 | 创建一族相关产品 |
| 变化点 | 具体产品由子类决定 | 产品系列整体切换 |
| 关键词 | 子类决定、延迟实例化 | 产品族、一系列、联合使用 |
建造者:复杂对象的过程与表示分离
建造者也叫生成器。它将复杂对象的构建过程和对象表示分离,使同样的构建过程可以创建不同表示。
课程例子是套餐制作:主餐、饮料、玩具等部件的制作流程相似,但不同套餐的具体表示不同。服务员可以调度厨师按步骤制作套餐,这里的“服务员”对应 Director,“厨师/生成器”对应 Builder。
classDiagram
class Director {
+construct()
}
class Builder {
+buildPartA()
+buildPartB()
+getResult()
}
class ConcreteBuilder
class Product
Director --> Builder : uses
Builder <|.. ConcreteBuilder
ConcreteBuilder --> Product : builds建造者题目常出现:
- 复杂对象由多个部分组成。
- 构建过程相同,但产品表示不同。
- 需要把构建步骤抽象出来。
- 类图中有
Builder、Director、buildPart()、getResult()。
原型:通过克隆已有对象创建
原型模式通过复制已有实例来创建新对象,又叫克隆模式。
适合场景:对象创建成本较高,或者对象状态组合有限,可以先保存原型,再复制并按需要微调。它的关键词是 clone、复制、拷贝、减少实例化开销。
classDiagram
class Prototype {
+clone()
}
class ConcretePrototype
class Client
Prototype <|.. ConcretePrototype
Client ..> Prototype : clone()注意:原型不是“完全不用初始化”,而是用复制替代从头创建;如果新对象和原型有差异,还要修改差异部分。
单例:唯一实例与全局访问点
单例模式保证一个类只有一个实例,并提供访问它的全局访问点。
典型实现会包含静态实例、私有构造方法、静态访问方法。考试不常要求写完整代码,但会考“唯一实例”“全局访问点”。
classDiagram
class Singleton {
-static instance
-Singleton()
+static getInstance()
}单例的好处是控制实例数量,避免多个对象产生冲突;代价是全局状态可能增加测试和扩展难度。现代设计中会更谨慎使用单例,很多场景会改用依赖注入管理生命周期。
创建型模式辨析
| 题干描述 | 应选模式 | 排除思路 |
|---|---|---|
| 一个类仅有一个实例 | 单例 | 不是建造者,也不是原型 |
| 复杂对象的构建与表示分离 | 建造者 | 不是抽象工厂,抽象工厂重点是产品族 |
| 子类指定创建的对象 | 工厂方法 | 不是抽象工厂,工厂方法通常返回一个产品 |
| 一系列相关产品需要联合使用 | 抽象工厂 | 不是工厂方法 |
| 通过复制已有实例创建对象 | 原型 | 不是单例,原型可以有多个复制对象 |
例题
自查要点
- 抽象工厂和工厂方法的核心区别是什么?
- 建造者模式中的 Director 和 Builder 分别负责什么?
- 原型模式为什么能减少创建开销?
- 单例模式为什么既有用,也容易带来全局状态问题?