原型模式 (Prototype)
原型模式 是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化。
意图
- 使用原型实例指定要创建的对象类型,并通过复制该原型来生成新对象。
- 提供一种高效创建对象的方式,尤其是当对象的创建成本较高时。
使用场景
- 对象创建成本高 :
- 如果直接实例化对象开销较大(如对象初始化需要大量资源),可以通过克隆已存在的对象快速生成新实例。
- 复杂对象需要重复创建 :
- 当对象的结构较复杂,需要创建多个相似对象时。
- 避免直接依赖具体类 :
- 原型模式通过复制实例而不是直接依赖构造函数,可以减少对具体类的依赖。
参与者角色
- 原型接口 (Prototype)
- 定义一个克隆方法,用于复制对象。
- 具体原型 (Concrete Prototype)
- 实现原型接口,定义克隆方法,返回当前实例的复制品。
- 客户端 (Client)
- 使用原型接口创建新对象,而不直接依赖具体类。
示例代码
以下示例展示了如何使用原型模式创建几种不同类型的图形对象。
cpp
#include <iostream>
#include <memory>
#include <string>
// 原型接口
class Shape {
public:
virtual ~Shape() {}
virtual std::unique_ptr<Shape> clone() const = 0;
virtual void draw() const = 0;
};
// 具体原型:圆形
class Circle : public Shape {
private:
int radius;
public:
Circle(int r) : radius(r) {}
// 实现克隆方法
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Circle>(*this);
}
void draw() const override {
std::cout << "Drawing a Circle with radius: " << radius << std::endl;
}
};
// 具体原型:矩形
class Rectangle : public Shape {
private:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
// 实现克隆方法
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Rectangle>(*this);
}
void draw() const override {
std::cout << "Drawing a Rectangle with width: " << width
<< " and height: " << height << std::endl;
}
};
// 客户端代码
int main() {
// 创建具体原型
std::unique_ptr<Shape> circlePrototype = std::make_unique<Circle>(10);
std::unique_ptr<Shape> rectanglePrototype = std::make_unique<Rectangle>(20, 30);
// 克隆原型
auto circle1 = circlePrototype->clone();
auto circle2 = circlePrototype->clone();
auto rectangle1 = rectanglePrototype->clone();
// 使用克隆对象
circle1->draw(); // 输出:Drawing a Circle with radius: 10
circle2->draw(); // 输出:Drawing a Circle with radius: 10
rectangle1->draw(); // 输出:Drawing a Rectangle with width: 20 and height: 30
return 0;
}
代码解析
1. 原型接口
- 定义了
clone()
方法,用于创建当前对象的副本:
cpp
virtual std::unique_ptr<Shape> clone() const = 0;
2. 具体原型类
Circle
和Rectangle
是具体原型类,分别实现了clone()
方法,返回自身的副本:
cpp
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Circle>(*this);
}
3. 客户端
- 客户端通过调用
clone()
方法创建对象,而无需直接依赖具体类:
cpp
auto circle1 = circlePrototype->clone();
circle1->draw();
优缺点
优点
- 对象复制高效 :
- 直接复制对象比重新实例化速度更快。
- 减少依赖 :
- 客户端代码无需依赖具体类的构造函数。
- 动态创建对象 :
- 可在运行时动态生成对象,而不是在编译时确定。
缺点
- 深拷贝复杂性 :
- 如果对象中包含指针或其他复杂资源,需特别注意深拷贝逻辑。
- 实现复杂 :
- 需要为每个类实现
clone()
方法,增加了一定的代码量。
- 需要为每个类实现
适用场景
- 需要大量相似对象:如图形编辑器中需要重复创建类似图形。
- 对象初始化成本高:如大型游戏中加载模型、地图等资源。
- 需要动态生成对象:如根据配置文件动态生成对象。
改进与扩展
-
深拷贝支持
- 如果对象包含动态内存或指针成员变量,需要实现深拷贝以避免资源共享问题。
-
结合原型注册表
- 使用注册表保存所有原型实例,根据名称或类型动态克隆对象:
cppclass PrototypeRegistry { private: std::unordered_map<std::string, std::unique_ptr<Shape>> prototypes; public: void registerPrototype(const std::string& name, std::unique_ptr<Shape> prototype) { prototypes[name] = std::move(prototype); } std::unique_ptr<Shape> create(const std::string& name) const { return prototypes.at(name)->clone(); } };
总结
原型模式通过复制已有对象来快速创建新对象,避免了复杂的初始化逻辑,并减少了对具体类的依赖。
它适用于需要动态生成大量相似对象或高效创建对象的场景。