原型设计模式详解
原型设计模式是一种创建型设计模式,它通过复制现有对象(原型)来创建新对象,而不是使用传统的构造函数。这种模式适用于需要高效创建对象副本的场景,特别是当对象创建成本较高时。
1. 功能和作用
- 功能:原型模式允许客户端通过复制一个已存在的对象(原型)来创建新对象,而无需知道具体创建细节。这避免了重复初始化对象的开销。
- 作用 :
- 提高性能:当对象创建涉及复杂计算或资源分配时,直接复制比重新创建更高效。
- 支持动态对象创建:系统可以在运行时根据需要克隆对象,增加灵活性。
- 隔离创建过程:客户端不依赖于具体类,只需通过原型接口操作。
2. 原理
原型模式的核心原理是基于对象克隆。它定义一个原型接口(通常是抽象类),声明一个克隆方法(如 clone())。具体类实现这个方法,返回自身的一个副本。克隆可以是浅拷贝(复制引用)或深拷贝(复制整个对象结构),取决于实现。
3. 为什么这么设计
这种设计解决了以下问题:
- 避免创建开销:当对象初始化涉及大量资源(如数据库连接或复杂计算)时,直接复制比重建更高效。例如,在游戏中创建多个相似角色时,复制原型比重新加载资源更快。
- 动态性和灵活性:系统可以在运行时决定克隆哪个对象,支持动态添加新对象类型。
- 减少耦合:客户端只依赖原型接口,不绑定具体类,便于扩展和维护。
4. 使用场景
原型模式适用于:
- 对象创建成本高,需要高效复制。
- 系统需要独立于对象创建过程。
- 对象类型在运行时才确定。
- 示例场景:图形编辑器中的形状复制、配置模板的复用、游戏中的敌人克隆。
5. 使用方式
使用原型模式的基本步骤:
- 定义一个抽象原型类,声明克隆方法。
- 实现具体原型类,重写克隆方法以返回自身副本。
- 客户端通过调用原型对象的
clone()方法创建新对象。 - 可选:使用注册表管理原型对象,便于访问。
6. 类图描述方法和属性
类图描述原型模式的结构:
- Prototype (抽象类):定义克隆接口。
- 方法:
virtual Prototype* clone() const = 0(纯虚函数)。
- 方法:
- ConcretePrototype (具体类):继承 Prototype,实现克隆方法。
- 属性:例如
int data(具体状态)。 - 方法:
ConcretePrototype* clone() const override(实现克隆逻辑)。
- 属性:例如
- Client (客户端):使用原型对象创建副本。
- 方法:例如
void usePrototype(Prototype* proto)。
- 方法:例如
关系:
- ConcretePrototype 继承 Prototype。
- Client 依赖于 Prototype 接口。
如下所示:

7. 使用时序图描述对象的工作流程
时序图描述客户端如何通过原型对象创建新对象:
- 参与者:Client、Prototype(或 ConcretePrototype)。
- 流程 :
- Client 请求 Prototype 对象(例如通过工厂或直接持有)。
- Client 调用
clone()方法:Client -> Prototype: clone()。 - Prototype 创建自身副本:
Prototype --> Prototype: 创建新对象。 - Prototype 返回副本:
Prototype --> Client: 返回新对象。 - Client 使用新对象。
示例时序:
- Client 持有 ConcretePrototype 实例。
- Client 调用
clone(),获取一个新 ConcretePrototype 对象。 - 新对象状态与原对象相同。
如下所示:

8. 使用 C++ 语言编写原型模式
以下是一个完整的 C++ 实现,包括原型模式的核心类和测试代码。代码可编译运行,使用深拷贝确保对象独立性。
cpp
#include <iostream>
#include <string>
// 抽象原型类
class Prototype {
public:
virtual ~Prototype() {}
virtual Prototype* clone() const = 0; // 克隆方法
virtual void display() const = 0; // 用于测试显示
};
// 具体原型类
class ConcretePrototype : public Prototype {
private:
int data; // 示例属性
public:
ConcretePrototype(int data) : data(data) {}
// 实现克隆方法(深拷贝)
Prototype* clone() const override {
return new ConcretePrototype(*this); // 调用拷贝构造函数
}
void display() const override {
std::cout << "ConcretePrototype with data: " << data << std::endl;
}
// 设置数据方法(用于测试)
void setData(int newData) {
data = newData;
}
};
// 客户端使用
int main() {
// 创建原型对象
ConcretePrototype* original = new ConcretePrototype(10);
std::cout << "Original object: ";
original->display();
// 克隆原型对象
Prototype* cloned = original->clone();
std::cout << "Cloned object: ";
cloned->display();
// 修改原对象,验证深拷贝
original->setData(20);
std::cout << "After modification - Original: ";
original->display();
std::cout << "After modification - Cloned: ";
cloned->display(); // 应显示原值,证明独立
// 清理
delete original;
delete cloned;
return 0;
}
编译和运行:
-
保存为
prototype.cpp。 -
编译:
g++ prototype.cpp -o prototype(使用 C++ 编译器如 GCC)。 -
运行:
./prototype。 -
输出 :
Original object: ConcretePrototype with data: 10 Cloned object: ConcretePrototype with data: 10 After modification - Original: ConcretePrototype with data: 20 After modification - Cloned: ConcretePrototype with data: 10
输出证明克隆对象独立于原对象(深拷贝)。
9. 总结优缺点
优点:
- 性能高效:通过复制避免高成本创建,如大型对象初始化。
- 动态扩展:支持在运行时添加新原型类型。
- 松耦合:客户端只依赖接口,便于维护和扩展。
- 简化对象创建:无需复杂工厂或构建逻辑。
缺点:
- 深拷贝复杂性:如果对象包含指针或资源,需手动实现深拷贝,易出错。
- 适用性有限:不适合所有对象,如单例或状态依赖对象。
- 额外开销:管理原型注册表可能增加系统复杂性。
10. 改进建议
- 使用注册表:引入一个原型管理器(如 map),存储和检索原型对象,便于客户端访问。
- 优化克隆逻辑:确保深拷贝正确处理嵌套对象和资源,避免内存泄漏。
- 结合其他模式:与工厂模式结合,提供统一创建接口。
- 自动化工具 :在语言支持克隆的框架中(如 Java 的
Cloneable),利用内置机制简化实现。
通过原型模式,开发者可以高效创建对象副本,特别适合资源敏感场景。但需注意克隆实现的细节以避免潜在问题。