原型模式

它允许对象通过复制(克隆)自身来创建新的对象,而不是通过 new 关键字直接实例化(通过拷贝构造来实现对象的创建)。这样可以提高对象创建的效率,尤其是对于创建代价较高的对象,避免每次都重新初始化。

如果所需对象与预先配置的对象相同, 那么你只需克隆原型即可, 无需新建一个对象。

例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <memory>
#include <unordered_map>

// 原型接口
class Document {
public:
virtual ~Document() = default;
virtual std::unique_ptr<Document> clone() const = 0;
virtual void show() const = 0;
};

// 具体原型:文本文档
class TextDocument : public Document {
public:
explicit TextDocument(std::string content) : content(std::move(content)) {}

// 克隆自身
std::unique_ptr<Document> clone() const override {
return std::make_unique<TextDocument>(*this); // 触发拷贝构造
}

void show() const override {
std::cout << "Text Document: " << content << std::endl;
}

private:
std::string content;
};

// 具体原型:图像文档
class ImageDocument : public Document {
public:
explicit ImageDocument(std::string imagePath) : imagePath(std::move(imagePath)) {}

// 克隆自身
std::unique_ptr<Document> clone() const override {
return std::make_unique<ImageDocument>(*this); // 触发拷贝构造
}

void show() const override {
std::cout << "Image Document: " << imagePath << std::endl;
}

private:
std::string imagePath;
};

// 原型管理器
class PrototypeManager {
public:
void registerPrototype(const std::string& key, std::unique_ptr<Document> prototype) {
prototypes[key] = std::move(prototype);
}

std::unique_ptr<Document> create(const std::string& key) {
if (prototypes.find(key) != prototypes.end()) {
return prototypes[key]->clone();
}
return nullptr;
}

private:
std::unordered_map<std::string, std::unique_ptr<Document>> prototypes;
};

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int main() {
PrototypeManager manager;

// 注册原型
manager.registerPrototype("text", std::make_unique<TextDocument>("Hello, Prototype!"));
manager.registerPrototype("image", std::make_unique<ImageDocument>("image.png"));

// 通过克隆创建新对象
auto doc1 = manager.create("text");
auto doc2 = manager.create("text");

if (doc1) doc1->show();
if (doc2) doc2->show();

doc1->setData("test");

if (doc1) doc1->show();
if (doc2) doc2->show();

auto doc3 = manager.create("text");
if (doc3) doc3->show();

return 0;
}

/*

Text Document: Hello, Prototype!
Text Document: Hello, Prototype!
Text Document: test
Text Document: Hello, Prototype!
Text Document: Hello, Prototype!

*/

把创建好的对象存储在容器中(unordered_map),需要该对象就从容器中“克隆”(拷贝)一份出来,得到的这个对象和原对象是两个独立的对象。

注意:可能导致深拷贝问题,即如果对象包含指针或动态资源,可能需要手动实现深拷贝。

如果 clone() 实现的是浅拷贝,则两个对象共享相同的资源;如果实现的是深拷贝,则两个对象完全独立,互不影响。