目录
原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象(原型)来创建新对象,而无需依赖显式的类实例化过程。这种模式特别适用于创建成本较高或实例化过程复杂的对象,通过克隆现有对象可以显著提高性能。
一、模式结构与核心角色
原型模式包含以下核心角色:
- 抽象原型(Prototype):定义克隆自身的接口。
- 具体原型(Concrete Prototype):实现克隆方法,返回自身的副本。
- 客户端(Client):通过调用原型对象的克隆方法来创建新对象。
二、实现要点
抽象原型接口:声明克隆方法,通常为纯虚函数,例如:
class Prototype { public: virtual Prototype* clone() const = 0; virtual ~Prototype() {} };
具体原型实现:实现克隆方法,返回自身的副本,例如:
class ConcretePrototype : public Prototype { private: int data; public: ConcretePrototype(int value) : data(value) {} // 深拷贝实现 Prototype* clone() const override { return new ConcretePrototype(data); } };
客户端使用:通过克隆现有对象创建新对象,例如:
Prototype* prototype = new ConcretePrototype(10); Prototype* clone = prototype->clone();
三、深拷贝与浅拷贝
在实现原型模式时,需要特别注意深拷贝(Deep Copy)和浅拷贝(Shallow Copy)的区别:
- 浅拷贝:只复制对象本身和基本数据类型,引用类型(如指针、引用)指向原对象的内存地址。
- 深拷贝:复制对象及其所有引用类型的内容,创建独立的内存副本。
示例(深拷贝):
class Prototype
{
protected:
std::string* data;
public:
Prototype(const std::string& value) : data(new std::string(value)) {}
// 深拷贝构造函数
Prototype(const Prototype& other) : data(new std::string(*other.data)) {}
~Prototype() { delete data; }
virtual Prototype* clone() const = 0;
};
class ConcretePrototype : public Prototype
{
public:
ConcretePrototype(const std::string& value) : Prototype(value) {}
// 深拷贝克隆方法
Prototype* clone() const override
{
return new ConcretePrototype(*this);
}
};
四、原型管理器(Prototype Manager)
当系统中有多个原型对象时,可以使用原型管理器集中管理这些原型:
#include <unordered_map>
#include <string>
class PrototypeManager
{
private:
std::unordered_map<std::string, Prototype*> prototypes;
public:
void addPrototype(const std::string& key, Prototype* prototype)
{
prototypes[key] = prototype;
}
Prototype* getPrototype(const std::string& key)
{
return prototypes[key]->clone();
}
~PrototypeManager()
{
for (auto& pair : prototypes)
{
delete pair.second;
}
}
};
五、应用场景
- 对象创建成本高:当对象的初始化过程涉及复杂计算、IO 操作或网络请求时,例如:
- 数据库连接对象。
- 加载大文件的文档对象。
- 动态创建对象:在运行时根据需要动态创建对象,例如:
- 游戏中的角色复制。
- 配置对象的克隆。
- 避免继承层级过深:通过克隆现有对象而非创建子类来定制对象。
六、示例代码:图形克隆系统
以下是一个图形克隆系统的示例,使用原型模式:
#include <iostream>
#include <unordered_map>
#include <memory>
// 抽象原型:图形
class Shape
{
protected:
std::string type;
public:
virtual ~Shape() {}
std::string getType() const { return type; }
virtual void draw() const = 0;
virtual Shape* clone() const = 0;
};
// 具体原型:圆形
class Circle : public Shape
{
public:
Circle() { type = "Circle"; }
void draw() const override { std::cout << "Drawing a circle." << std::endl; }
Shape* clone() const override { return new Circle(*this); }
};
// 具体原型:矩形
class Rectangle : public Shape
{
public:
Rectangle() { type = "Rectangle"; }
void draw() const override { std::cout << "Drawing a rectangle." << std::endl; }
Shape* clone() const override { return new Rectangle(*this); }
};
// 原型管理器
class ShapeCache
{
private:
std::unordered_map<std::string, Shape*> shapeMap;
public:
~ShapeCache()
{
for (auto& pair : shapeMap)
{
delete pair.second;
}
}
Shape* getShape(const std::string& shapeId)
{
Shape* cachedShape = shapeMap[shapeId];
return cachedShape->clone();
}
void loadCache()
{
Circle* circle = new Circle();
shapeMap["Circle"] = circle;
Rectangle* rectangle = new Rectangle();
shapeMap["Rectangle"] = rectangle;
}
};
// 客户端代码
int main()
{
ShapeCache shapeCache;
shapeCache.loadCache();
// 克隆圆形
std::unique_ptr<Shape> clonedCircle(shapeCache.getShape("Circle"));
clonedCircle->draw(); // 输出: Drawing a circle.
// 克隆矩形
std::unique_ptr<Shape> clonedRectangle(shapeCache.getShape("Rectangle"));
clonedRectangle->draw(); // 输出: Drawing a rectangle.
return 0;
}
七、优缺点
优点:
- 提高性能:避免重复初始化过程,直接复制现有对象。
- 简化对象创建:无需依赖具体类,通过接口克隆对象。
- 动态添加或删除原型:运行时可以灵活管理原型对象。
缺点:
- 实现复杂:需要正确实现深拷贝,尤其是涉及指针或引用时。
- 克隆方法传播:每个子类都需要实现克隆方法,可能导致代码冗余。
八、与其他模式的关系
- 工厂模式:工厂模式通过工厂类创建对象,而原型模式通过克隆现有对象创建新对象。
- 抽象工厂模式:抽象工厂模式可以结合原型模式,通过克隆方法创建产品族。
- 构建器模式:构建器模式注重分步构建复杂对象,而原型模式注重复制现有对象。
九、C++ 实现注意事项
- 虚析构函数:确保抽象原型类有虚析构函数,防止内存泄漏。
- 移动语义:在 C++11 及以后,可以使用移动构造函数和移动赋值运算符优化深拷贝性能。
- 智能指针:考虑使用智能指针(如
std::unique_ptr
或std::shared_ptr
)管理克隆对象的生命周期。
原型模式是 C++ 中处理复杂对象创建的有效工具,尤其适用于需要频繁创建相似对象的场景,通过复制现有对象可以显著提高效率和代码灵活性。