一、定义
Prototype模式是一种对象创建型模式,它用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
- 由原型对象自身创建目标对象。即对象创建这一动作发自原型对象本身。
- 目标对象是原型对象的一个克隆。即通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。
- 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。
关于深浅克隆,需要理解c++拷贝复制函数,请参考:c++拷贝构造函数详解
二、角色
1.抽象原型类:
规定了具体原型对象必须实现的接口。
2.具体原型类:
实现抽象原型类的 clone() 方法,它是可被复制的对象。
3.访问类:
使用具体原型类中的 clone() 方法来复制新的对象。
UML类图如下:
三、实现
#include<iostream>
using namespace std;
//抽象原型
class Person{
public:
virtual Person* clone() = 0;
virtual void printMSG() = 0;
};
//具体原型
class JavaPragramer:public Person{
private:
string m_name;
int m_age;
char *m_motto;
public:
JavaPragramer(){
}
JavaPragramer(const string name,const int age,const char* motto){
this->m_name = name;
this->m_age = age;
if(motto == nullptr){
this->m_motto = new char[1];
this->m_motto[0] = '\0';
}else{
int len = strlen(motto) + 1;
this->m_motto = new char[len];
strcpy(this->m_motto,motto);
}
}
~JavaPragramer(){
if(this->m_motto != nullptr){
delete this->m_motto;
this->m_motto = nullptr;
}
}
//拷贝构造函数
JavaPragramer(const JavaPragramer &p){
this->m_name = p.m_name;
this->m_age = p.m_age;
//存在指针成员变量,进行深拷贝
if(p.m_motto == nullptr){
this->m_motto = new char[1];
this->m_motto[0] = '\0';
}else{
int len = strlen(p.m_motto) + 1;
this->m_motto = new char[len];
strcpy(this->m_motto,p.m_motto);
}
}
//克隆
Person* clone(){
Person * p = new JavaPragramer(*this);//通过拷贝构造函数实现克隆
return p;
}
void printMSG(){
cout<<this->m_name.c_str() <<" : "<<this->m_age<<" : "<<this->m_motto<<endl;
}
};
class CplusplusPragramer:public Person{
private:
string m_name;
int m_age;
char *m_motto;
public:
CplusplusPragramer(){
}
CplusplusPragramer(const string name,const int age,const char* motto){
this->m_name = name;
this->m_age = age;
if(motto == nullptr){
this->m_motto = new char[1];
this->m_motto[0] = '\0';
}else{
int len = strlen(motto) + 1;
this->m_motto = new char[len];
strcpy(this->m_motto,motto);
}
}
~CplusplusPragramer(){
if(this->m_motto != nullptr){
delete this->m_motto;
this->m_motto = nullptr;
}
}
//拷贝构造函数
CplusplusPragramer(const CplusplusPragramer &p){
this->m_name = p.m_name;
this->m_age = p.m_age;
//存在指针成员变量,进行深拷贝
if(p.m_motto == nullptr){
this->m_motto = new char[1];
this->m_motto[0] = '\0';
}else{
int len = strlen(p.m_motto) + 1;
this->m_motto = new char[len];
strcpy(this->m_motto,p.m_motto);
}
}
//克隆
Person* clone(){
Person * p = new CplusplusPragramer(*this);
return p;
}
void printMSG(){
cout<<this->m_name.c_str() <<" : "<<this->m_age<<" : "<<this->m_motto<<endl;
}
};
int main(){
//创建一个java实例原型
Person *javaPragramer = new JavaPragramer("Tom",22,"Java是最好的语言");
javaPragramer->printMSG();
//克隆person
Person *javaPragramer2 = javaPragramer->clone();
javaPragramer2->printMSG();
delete javaPragramer;
delete javaPragramer2;
//创建一个c++实例原型
Person *cplusplusPragramer = new CplusplusPragramer("Jack",25,"c++是改变世界的语言");
cplusplusPragramer->printMSG();
//克隆person
Person *cplusplusPragramer2 = cplusplusPragramer->clone();
cplusplusPragramer2->printMSG();
delete cplusplusPragramer;
delete cplusplusPragramer2;
return 0 ;
}
四、应用场景
1.类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
2.通过new一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式。
3.一个对象需要提供给其他对象访问,而且各个调用者可能需要修改其值,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
五、与其他创建型模式区别
相同的点:
Prototype模式、Builder模式、AbstractFactory模式都是通过一个类(对象实例)来专门负责对象的创建工作。
不同点:
Builder模式重在复杂对象的一步步创建。
AbstractFactory模式重在产生多个相互依赖类的对象。
Prototype模式重在从自身复制自己创建新类。