前言:
今天我们来聊一聊创建型模式的一种:原型模式;
一、原理及C++示例代码
原型模式是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需使代码依赖它们所属的类。这种模式对于创建复杂对象或者那些创建过程中涉及很多成本的对象非常有用。
以下是一个简单的C++代码示例,演示了原型模式的实现原理:
#include <iostream>
#include <unordered_map>
// 抽象原型类
class Prototype {
public:
virtual Prototype* clone() = 0;
virtual void printInfo() = 0;
virtual ~Prototype() {}
};
// 具体原型类
class ConcretePrototype : public Prototype {
public:
ConcretePrototype(int id) : id_(id) {}
// 实现克隆方法
Prototype* clone() override {
return new ConcretePrototype(*this);
}
// 实现打印信息方法
void printInfo() override {
std::cout << "ConcretePrototype, id: " << id_ << std::endl;
}
private:
int id_;
};
// 原型管理器
class PrototypeManager {
public:
// 添加原型
void addPrototype(const std::string& key, Prototype* prototype) {
prototypes_[key] = prototype;
}
// 获取原型
Prototype* getPrototype(const std::string& key) {
return prototypes_[key]->clone();
}
private:
std::unordered_map<std::string, Prototype*> prototypes_;
};
int main() {
// 创建原型管理器
PrototypeManager manager;
// 添加具体原型对象
manager.addPrototype("p1", new ConcretePrototype(1));
manager.addPrototype("p2", new ConcretePrototype(2));
// 获取并克隆原型对象
Prototype* clonedP1 = manager.getPrototype("p1");
Prototype* clonedP2 = manager.getPrototype("p2");
// 打印信息
clonedP1->printInfo();
clonedP2->printInfo();
// 释放资源
delete clonedP1;
delete clonedP2;
return 0;
}
在上面的示例中,我们定义了一个抽象原型类Prototype和一个具体原型类ConcretePrototype。PrototypeManager类用于管理原型对象。在main函数中,我们创建了具体原型对象并将其添加到原型管理器中,然后通过克隆方法获取原型对象的副本,并打印信息。
二、原型模式结构图
整个结构可以用如下的结构图表示:
---------------- ------------------------
| Client |------->| PrototypeManager |
---------------- ------------------------
| prototypes_ |
------------------------
| +addPrototype() |
| +getPrototype() |
------------------------
/\
|
|
------------------------
| Prototype |
------------------------
| +clone() |
| +printInfo() |
------------------------
/ \
------------------------ ------------------------
| ConcretePrototype 1 | | ConcretePrototype 2 |
------------------------ ------------------------
| +clone() | | +clone() |
| +printInfo() | | +printInfo() |
------------------------ ------------------------
三、原型模式使用场景
原型模式适合在以下场景中使用:
-
当需要创建的对象类型由一个原型对象确定,而且需要避免构建和配置对象的子类层次结构时,可以使用原型模式。例如,通过克隆操作创建新对象,而不是通过构造函数创建。
-
当需要动态配置对象时,可以使用原型模式。原型对象可以作为模板,通过克隆操作创建新对象,并且可以动态修改原型对象的属性,从而影响新对象的属性。
-
当需要减少子类的构造时,可以使用原型模式。通过克隆操作创建新对象,避免了子类构造过程中的复杂逻辑。
-
当需要避免创建大量相似对象实例的开销时,可以使用原型模式。通过克隆已有对象来创建新对象,避免了重复的初始化过程,提高了性能。
总的来说,原型模式适合在需要动态创建对象,避免重复初始化过程,动态配置对象属性等场景下使用。
四、原型模式优缺点
原型模式的优点包括:
-
减少对象的初始化开销:通过克隆操作创建新对象,避免了重复的初始化过程,提高了性能。
-
动态配置对象:原型对象可以作为模板,通过克隆操作创建新对象,并且可以动态修改原型对象的属性,从而影响新对象的属性。
-
减少子类的构造:通过克隆操作创建新对象,避免了子类构造过程中的复杂逻辑。
原型模式的缺点包括:
-
需要对每一个类都实现克隆方法,因此需要对现有的类进行一定的修改。
-
如果克隆的对象包含了循环引用,可能会导致无限循环克隆,需要特别注意。
总的来说,原型模式适合在需要动态创建对象,避免重复初始化过程,动态配置对象属性等场景下使用。但在实际应用中,需要注意对现有类的修改和对循环引用的处理。
4
5 |-----|
+---+ | |
| | | |
| | 3 3 | |
| | | |
| +---+ ----- | |
| | | | | | |----|3
2 | | 2 | | 2 | | | |
| | | | | | | |
+---+ | ----+ | +---+ | | | |
| | | | | | | | | |
1 | | 1 1 | | 1 | | 1 | | | |
| | | | | | | | | |
+---+ +---+ +---+ +---+ +---+ | | | |
| | | | | | | |
0 | | 0 0 | | 0 | | | |
| | | | | | | |
+---+ +-------+ +---+ | +--- | |+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18