一、定義
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模式重在從自身複製自己創建新類。