原型模式的核心是通过克隆已有对象来创建新对象,无需依赖具体类的构造逻辑。在复杂系统中,我们往往需要管理多种不同类型的原型对象,通过统一的标识就能获取对应的原型并生成新实例,这就需要结合注册管理和原型对象工厂来实现。

原型模式基础实现
首先我们需要定义原型基类,所有可被克隆的原型对象都需要继承这个基类,实现克隆方法。基类需要声明纯虚函数clone,用于返回当前对象的副本。
// 原型基类
class Prototype {
public:
virtual ~Prototype() = default;
// 克隆方法,返回当前对象的副本
virtual Prototype* clone() const = 0;
// 获取原型类型标识,用于注册和查找
virtual std::string getType() const = 0;
};
注册管理模块设计
注册管理的核心是把原型对象的类型标识和对应的原型实例关联起来,提供注册、注销、查询的能力。我们可以使用std::unordered_map来存储映射关系,键为类型标识字符串,值为原型对象的指针。
#include <unordered_map>
#include <string>
#include <memory>
#include <iostream>
// 注册管理器类
class PrototypeRegistry {
private:
// 存储类型标识到原型对象的映射
std::unordered_map<std::string, Prototype*> registry;
public:
~PrototypeRegistry() {
// 释放所有注册的原型对象
for (auto& pair : registry) {
delete pair.second;
}
}
// 注册原型对象
bool registerPrototype(Prototype* prototype) {
if (prototype == nullptr) {
return false;
}
std::string type = prototype->getType();
// 如果已存在同类型原型,先释放旧的
if (registry.find(type) != registry.end()) {
delete registry[type];
}
registry[type] = prototype;
return true;
}
// 注销指定类型的原型
void unregisterPrototype(const std::string& type) {
auto it = registry.find(type);
if (it != registry.end()) {
delete it->second;
registry.erase(it);
}
}
// 获取指定类型的原型对象,返回的是原型本身,用于克隆
Prototype* getPrototype(const std::string& type) const {
auto it = registry.find(type);
if (it != registry.end()) {
return it->second;
}
return nullptr;
}
};
具体原型类实现
接下来我们定义几个具体的原型类,继承Prototype基类,实现clone和getType方法。每个具体原型类对应一种可创建的对象类型。
// 具体原型类1:圆形对象
class CirclePrototype : public Prototype {
private:
int radius;
public:
CirclePrototype(int r = 0) : radius(r) {}
// 实现克隆方法,返回新的CirclePrototype实例
Prototype* clone() const override {
return new CirclePrototype(*this);
}
std::string getType() const override {
return "Circle";
}
void setRadius(int r) {
radius = r;
}
void printInfo() const {
std::cout << "Circle radius: " << radius << std::endl;
}
};
// 具体原型类2:矩形对象
class RectanglePrototype : public Prototype {
private:
int width;
int height;
public:
RectanglePrototype(int w = 0, int h = 0) : width(w), height(h) {}
Prototype* clone() const override {
return new RectanglePrototype(*this);
}
std::string getType() const override {
return "Rectangle";
}
void setSize(int w, int h) {
width = w;
height = h;
}
void printInfo() const {
std::cout << "Rectangle width: " << width << ", height: " << height << std::endl;
}
};
原型对象工厂实现
原型对象工厂封装了注册管理器和对象创建的逻辑,对外提供统一的接口,用户只需要传入类型标识,就能获取对应的新对象实例,无需关心原型的具体注册和克隆细节。
// 原型对象工厂
class PrototypeFactory {
private:
PrototypeRegistry registry;
public:
// 注册原型到工厂
void registerPrototype(Prototype* prototype) {
registry.registerPrototype(prototype);
}
// 根据类型标识创建新对象
Prototype* createObject(const std::string& type) {
Prototype* prototype = registry.getPrototype(type);
if (prototype != nullptr) {
// 调用原型的克隆方法生成新对象
return prototype->clone();
}
return nullptr;
}
};
完整使用示例
下面我们把所有模块组合起来,演示完整的注册管理和对象创建流程。首先注册不同类型的原型,然后通过工厂创建新对象,验证克隆效果。
int main() {
PrototypeFactory factory;
// 注册圆形原型和矩形原型
factory.registerPrototype(new CirclePrototype(5));
factory.registerPrototype(new RectanglePrototype(10, 20));
// 创建圆形对象并修改属性
CirclePrototype* circle = dynamic_cast<CirclePrototype*>(factory.createObject("Circle"));
if (circle != nullptr) {
circle->printInfo();
circle->setRadius(8);
circle->printInfo();
delete circle;
}
// 创建矩形对象并修改属性
RectanglePrototype* rect = dynamic_cast<RectanglePrototype*>(factory.createObject("Rectangle"));
if (rect != nullptr) {
rect->printInfo();
rect->setSize(15, 30);
rect->printInfo();
delete rect;
}
// 尝试创建不存在的类型
Prototype* unknown = factory.createObject("Triangle");
if (unknown == nullptr) {
std::cout << "Type Triangle not registered" << std::endl;
}
return 0;
}
方案优势与注意事项
这种实现方案的优势在于扩展性强,新增对象类型时只需要新增对应的原型类,然后注册到工厂即可,不需要修改工厂的创建逻辑。同时避免了复杂对象的重复初始化开销,克隆对象比重新构造效率更高。
需要注意的是,原型对象的生命周期由注册管理器管理,外部不需要手动释放注册的原型。而通过工厂创建的克隆对象,使用完成后需要由调用方负责释放,避免内存泄漏。另外如果原型对象包含指针成员,需要实现深拷贝,否则克隆时会出现指针共享的问题。