原型模式
原型模式的思路是,通过复制一个已有对象来获取一个或者多个相同或者相似的对象。
原型模式的工作原理是将一个原型对象传给要发动创建的对象------客户端,客户端通过请求原型对象复制本身来实现创建过程。按照工厂方式的思路去理解,就是创建的新工厂对象就是原型类自己。
软件系统中有些对象的创建过程比较复杂,且有时需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。
原型模式结构
原型式的结构包含以下几个角色:
- 抽象原型类(AbstractPrototype):声明克隆clone自身的接口
- 具体原型类(ConcretePrototype):实现clone接口
- 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例
浅拷贝、深拷贝
原型模式可以说是复制类本身,但这个复制不是代码的复制,而是将对象包含的所有属性都创建一份拷贝。但不同的复制操作,可能会产生两种不同的拷贝,分为浅拷贝和深拷贝。
浅拷贝
在浅拷贝中,如果原型对象的成员变量是值类型(如int、double、char等基本数据类型),将复制一份给拷贝对象;如果原型对象的成员变量是引用/指针,则将引用/指针指向的地址拷贝一份给拷贝对象,即原型对象和拷贝对象中的成员变量指向同一个地址。
深拷贝
在深拷贝中,无论原型对象中的成员变量是值类型还是指针/引用类型,都将复制一份给拷贝对象。
注意,深拷贝中,指针/引用对象也会被拷贝一份给拷贝对象。
原型模式实例
prototype_pattern.h
#include <iostream>
#include <string.h>
using namespace std;
//work model类
class WorkModel
{
public:
string modelName;
void setWorkModelName(string iName){
this->modelName = iName;
}
};
//抽象原型类PrototypeWork
class PrototypeWork
{
public:
PrototypeWork(){}
virtual PrototypeWork *clone() = 0;
private:
};
//具体原型类ConcreteWork
class ConcreteWork :public PrototypeWork
{
public:
ConcreteWork(){}
ConcreteWork(string iName, int iIdNum, string modelName){
this->name = iName;
this->idNum = iIdNum;
this->workModel = new WorkModel();
this->workModel->setWorkModelName(modelName);
}
ConcreteWork *clone(){
ConcreteWork *work = new ConcreteWork();
work->setName(this->name);
work->setIdNum(this->idNum);
work->workModel = this->workModel;
return work;
}
void setName(string iName){
this->name = iName;
}
void setIdNum(int iIdNum){
this->idNum = iIdNum;
}
void setModel(WorkModel *iWorkModel){
this->workModel = iWorkModel;
}
//打印work信息
void printWorkInfo(){
cout << "name:\t" << this->name << endl;
cout << "idNum:\t" << this->idNum << endl;
cout << "modelName:\t" << this->workModel->modelName << endl;
}
// private:
string name;
int idNum;
WorkModel *workModel;
};
prototype_pattern.cpp
#include "prototype_pattern.h"
int main()
{
// 赋值
#if 0
ConcreteWork *BasicWork = new ConcreteWork("basic", 1001, "basic_Model");
cout << "\nBasic Work:\n";
BasicWork->printWorkInfo();
ConcreteWork *CopyWork = BasicWork;
cout << "\nCopy Work:\n";
CopyWork->printWorkInfo();
cout << "\nCopy 完成后,记得跟新WorkName,Num以及ModelName!\n";
CopyWork->setName("CopyWork");
CopyWork->setIdNum(1002);
WorkModel *CopyModel = new WorkModel();
CopyModel->setWorkModelName("Copy_Model");
CopyWork->setModel(CopyModel);
cout << "\nBasic Work \n";
BasicWork->printWorkInfo();
cout << "\nCopy Work \n";
CopyWork->printWorkInfo();
delete CopyModel;
delete CopyWork;
#else
// 克隆
ConcreteWork *BasicWork = new ConcreteWork("basic", 1001, "Basic_Model");
cout << "\nBasic Work:\n";
BasicWork->printWorkInfo();
ConcreteWork *CopyWork = BasicWork->clone();
cout << "\nCopy Work:\n";
CopyWork->printWorkInfo();
cout << "\nCopy 完成后,记得跟新WorkName,Num以及ModelName !\n";
CopyWork->setName("CopyWork");
CopyWork->setIdNum(1002);
WorkModel *CopyModel = new WorkModel();
CopyModel->setWorkModelName("Copy_Model");
CopyWork->setModel(CopyModel);
//检查下是否改对了
cout << "\nBasic Work \n";
BasicWork->printWorkInfo();
cout << "\nCopy Work \n";
CopyWork->printWorkInfo();
delete BasicWork;
delete CopyModel;
delete CopyWork;
#endif
return 0;
}
注意比较赋值和拷贝之间的区别
原型模式总结
优点:
- 当创建新的对象实例较为复杂时,原型模式可以简化创建过程,提高创建对象的效率;
- 可扩展:模式中提供了抽象原型类,具体原型类可适当扩展;
- 创建结构简单:创建工厂即为原型对象本身
缺点:
- 深克隆代码较为复杂;
- 每一个类都得配备一个clone方法,且该方法位于类的内部,修改时违背开闭原则;
适用环境:
- 当创建新的对象实例较为复杂时,原型模式可以简化创建过程;
- 结合优点第3条,需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少几个的组合状态,通过复制原型对象得到新实例,比通过使用构造函数创建一个新实例会更加方便。