原型模式(Prototype):让对象自己复制自己
更新时间:2026-08-25。本文按"先看不用模式的困境 → 再用模式重构 → 类图对比分析"的结构,论述原型模式。可运行代码:demos/design-patterns/prototype。
一、问题场景:创建成本高或类型不确定的"复制"需求
文档编辑器里"复制一份带格式的图形"、游戏里"克隆一个敌人刷兵"、配置中心"复制一份配置再改两处"。共同点:与其从头构造,不如基于现有实例复制,且复制时不知道(或不关心)具体类型。
二、不使用模式:手工逐字段拷贝 / 按类型分支复制
cpp
// 客户端要知道具体类型,手工拷每个字段
Circle c2;
c2.setX(c1.getX()); c2.setY(c1.getY()); c2.setRadius(c1.getRadius());
// 类型多了:分支复制
if (type == CIRCLE) copyCircle(...); else if (type == RECT) copyRect(...);| 缺陷 | 说明 |
|---|---|
| 违反 DIP/OCP | 复制逻辑依赖所有具体类型,加类型就要加分支 |
| 字段拷贝易漏 | 新加字段忘拷 = 隐蔽 bug |
| 深拷贝易错 | 指针/容器成员处理错 → 悬垂或共享 |
| 复制逻辑散落 | 每个调用点各写一份 |
不使用模式的类图

三、使用模式:原型自备 clone(),复制交给对象自己
原型模式在基类声明 virtual clone(),每个具体类实现"复制自身"(天然知道自己的字段与内部结构,深浅拷贝自己做主);客户端只依赖抽象原型调用 clone()。
cpp
// shape.h —— 深浅拷贝对比的关键
class Shape {
public:
virtual std::unique_ptr<Shape> clone() const = 0;
virtual void draw() const = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
Circle(double r, std::shared_ptr<Style> st) : radius_(r), style_(std::move(st)) {}
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Circle>(*this); // 深拷贝:让 Style 也复制一份
// 若浅拷贝:style_ 直接共享,改一个全变
}
void draw() const override { /* ... */ }
private:
double radius_;
std::shared_ptr<Style> style_; // 复合成员,clone 时决定深浅
};
// 客户端:只依赖 Shape 抽象
std::unique_ptr<Shape> duplicate(const Shape& s) { return s.clone(); }使用模式的类图

深浅拷贝对比(本仓库内存视角)
| 拷贝策略 | 做法 | 后果 |
|---|---|---|
| 浅拷贝 | 指针成员直接共享 | 改一处影响所有"克隆体",可能悬垂(谁释放?) |
| 深拷贝 | 指针成员也复制一份 | 克隆体完全独立,内存翻倍 |
| 写时复制(COW) | 共享 + 修改时再复制 | 读多写少时省内存,需引用计数 |
选择依据:样式/配置等只读共享对象用浅拷贝+共享(省内存);会被独立修改的内部状态用深拷贝(保独立)。原型模式的 clone() 正是把这种策略决策收进类内部。
四、类图对比与分析
| 维度 | 不使用(逐字段/分支复制) | 使用原型 |
|---|---|---|
| 依赖 | 客户端依赖所有具体类型 | 只依赖抽象 Shape |
| 扩展新类型 | 复制分支要改 | 新类型实现 clone() 即可 |
| 字段漏拷 | 容易(散落拷贝点) | 不可能(类内部 *this 拷贝构造) |
| 深浅拷贝策略 | 各调用点各自为政 | 类内统一决策 |
| 创建成本 | 每次都从头构造 | 复制原型,可预置"样板原型" |
分析结论:原型把"复制"从调用方的手工劳动变成原型自身的能力,顺带解决了"类型未知时如何复制"(多态 clone)。代价是要求类可复制(深拷贝正确性在类内维护)。
五、适用边界
| 适用 | 不适用 |
|---|---|
| 创建成本高、基于已有对象改造 | 对象构造便宜、字段简单 |
| 类型在运行时才确定(插件/配置驱动) | 类型静态已知且少(直接 new + 拷贝构造) |
| 需要样板实例(原型池) | 类含不可复制资源(独占 fd/锁),须谨慎 |
与拷贝构造的区别:拷贝构造是语言机制(同类型复制);原型是模式(通过基类接口、跨类型多态复制)。原型模式内部通常就靠拷贝构造实现,但暴露的是抽象接口 clone()。
一句话总结
原型模式让对象通过 clone() 自己复制自己,客户端只依赖抽象原型——复制逻辑与深浅拷贝策略收进类内,类型未知也能复制;当创建昂贵且需基于现有实例变体时,它比手工逐字段拷贝更不易出错、更符合 OCP。