feat: Prototype

Implemented a demo for the Prototype.
This commit is contained in:
Yuki 2025-04-06 00:42:29 +08:00
parent f7eac92f68
commit 751033f2e9
Signed by: yuki
GPG Key ID: CF40579331C06C73
2 changed files with 68 additions and 0 deletions

62
06_prototype.cpp Normal file
View File

@ -0,0 +1,62 @@
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class Shape {
public:
virtual shared_ptr<Shape> clone() = 0;
virtual void draw() = 0;
};
class Circle : public Shape {
int x;
int y;
int r;
public:
Circle(int x, int y, int r): x(x), y(y), r(r) {}
virtual shared_ptr<Shape> clone() override {
// Default copy using the copy constructor.
// You can customize this to perform deep or shallow copy as needed.
return std::make_shared<Circle>(*this);
}
virtual void draw() override {
cout << "draw " << x << " " << y << " " << r << endl;
}
};
class Square : public Shape {
int x1;
int y1;
int x2;
int y2;
public:
Square(int x1, int y1, int x2, int y2) : x1(x1), y1(y1), x2(x2), y2(y2) {}
virtual shared_ptr<Shape> clone() override {
return std::make_shared<Square>(*this);
}
virtual void draw() override {
cout << "draw " << x1 << " " << y1 << " " << x2 << " " << y2 << endl;
}
};
int main() {
shared_ptr<Shape> c = make_shared<Circle>(1, 2, 3);
shared_ptr<Shape> s = make_shared<Square>(1, 2, 3, 4);
vector<shared_ptr<Shape>> origin_shapes = {c, s};
vector<shared_ptr<Shape>> clone_shapes;
for (auto shape : origin_shapes) {
// You can clone without knowing the concrete type of shape.
clone_shapes.push_back(shape->clone());
}
for (auto shape : clone_shapes) {
shape->draw();
}
}

View File

@ -33,3 +33,9 @@
单例模式是一种解决方案,这个类只通过静态的 `get_instance()` 提供统一访问方式,并且不提供拷贝构造和赋值操作。这样多个依赖的全局变量可以在这个类里管理。此外测试时可以只改内部实现,对外接口不变,提高了可维护性与可测试性。
具体实现上有一些技巧。为了只创建一次,可以用 `get_instance()` 中使用 `static` 变量(懒汉式),也可以这个类有一个 `static` 类成员(饿汉式),还可以用 `static` 指针成员,对于指针为空时(第一次访问)额外做初始化(需要注意创建时的线程安全,比如双检查)。
## 原型模式Prototype Pattern
有时需要在项目中创建副本,那么如何创建重复对象?很容易想到使用复制或赋值操作符,而不是普通的构造函数。但是这些方法没有多态性,如果很多子类需要复制就会有点麻烦。
解决方案也很简单,父类提供一种 `clone` 方法。这样客户端只需要调用 `clone` 方法,不需要知道这个类具体是什么。这种方法常配合对象注册表使用,通过维护一个原型缓存容器(如`map<string, Prototype*>`),根据名字/类型复制对象。