原型模式(Prototype)------ 复制粘贴大法好
大白话解释
你在画图软件里画了一个图形(比如一个圆),
想再来几个一样的:
👉 不用重新画!
👉 直接 Ctrl + C / Ctrl + V
然后改个颜色、大小就行。
原型模式:通过复制(克隆)现有对象来创建新对象,而不是重新走一遍复杂的创建流程。
常见场景:
- 游戏中批量生成相似的敌人(克隆模板怪)
- 配置对象的复制(复制一份默认配置再修改)
- 图形编辑器中复制图形元素
核心思路
- 定义克隆接口(
clone()方法) - 具体类实现
clone(),返回自身的副本 - 需要新对象时,不
new而是clone()
C++ 代码示例
cpp
#include <iostream>
#include <memory>
#include <vector>
#include <string>
// ==============================
// 原型基类:图形
// ==============================
class Shape {
public:
virtual ~Shape() = default;
int x = 0, y = 0;
std::string color;
virtual std::unique_ptr<Shape> clone() const = 0;
virtual void draw() const = 0;
};
// ==============================
// 圆形
// ==============================
class Circle : public Shape {
public:
int radius = 0;
Circle(int x, int y, int r, const std::string& c) {
this->x = x;
this->y = y;
this->radius = r;
this->color = c;
}
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Circle>(*this); // 拷贝构造
}
void draw() const override {
std::cout << "【圆】位置(" << x << "," << y
<< ") 半径:" << radius
<< " 颜色:" << color << "\n";
}
};
// ==============================
// 矩形
// ==============================
class Rectangle : public Shape {
public:
int width = 0;
int height = 0;
Rectangle(int x, int y, int w, int h, const std::string& c) {
this->x = x;
this->y = y;
this->width = w;
this->height = h;
this->color = c;
}
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Rectangle>(*this);
}
void draw() const override {
std::cout << "【矩形】位置(" << x << "," << y
<< ") 宽:" << width
<< " 高:" << height
<< " 颜色:" << color << "\n";
}
};
int main() {
// 创建一个原型(画好的图形)
auto circle = std::make_unique<Circle>(10, 10, 5, "红色");
std::cout << "=== 原始图形 ===\n";
circle->draw();
// ==============================
// 复制图形(Ctrl + C / Ctrl + V)
// ==============================
std::cout << "\n=== 复制多个图形 ===\n";
std::vector<std::unique_ptr<Shape>> shapes;
for (int i = 0; i < 3; ++i) {
auto copy = circle->clone(); // 克隆
copy->x += i * 10; // 改位置
copy->color = "蓝色"; // 改颜色
shapes.push_back(std::move(copy));
}
for (auto& s : shapes) {
s->draw();
}
// ==============================
// 不同图形也可以复制
// ==============================
std::cout << "\n=== 复制矩形 ===\n";
auto rect = std::make_unique<Rectangle>(0, 0, 20, 10, "绿色");
auto rectCopy = rect->clone();
rectCopy->x = 50;
rectCopy->color = "黄色";
rect->draw();
rectCopy->draw();
return 0;
}
输出:
=== 原始图形 ===
【圆】位置(10,10) 半径:5 颜色:红色
=== 复制多个图形 ===
【圆】位置(10,10) 半径:5 颜色:蓝色
【圆】位置(20,10) 半径:5 颜色:蓝色
【圆】位置(30,10) 半径:5 颜色:蓝色
=== 复制矩形 ===
【矩形】位置(0,0) 宽:20 高:10 颜色:绿色
【矩形】位置(50,0) 宽:20 高:10 颜色:黄色
浅拷贝 vs 深拷贝注意事项
cpp
// ⚠️ 如果对象包含指针,必须实现深拷贝
class Node {
public:
int value;
int* data; // 指针成员!
// 浅拷贝:两个对象共用同一块内存(危险!)
// 深拷贝:克隆一份新的内存
std::unique_ptr<Node> clone() const {
auto newNode = std::make_unique<Node>();
newNode->value = this->value;
newNode->data = new int(*this->data); // 深拷贝指针
return newNode;
}
};
优缺点
| 说明 | |
|---|---|
| ✅ 优点 | 避免重复的初始化代码,克隆比 new 更快 |
| ✅ 优点 | 可以在运行时动态生成对象 |
| ❌ 缺点 | 实现深拷贝比较麻烦,容易出 bug |
| ❌ 缺点 | 循环引用的对象克隆很复杂 |
一句话记忆
原型模式 = 图形编辑器复制粘贴,克隆已有图形,改一改就能用。