設計模式---對象創建模式之原型模式(prototype)
阿新 • • 發佈:2018-08-26
col 具體類 不同 new mark out 初始化 isp clas
一:概念
原型模式(Prototype Pattern) 實際上就是動態抽取當前對象運行時的狀態
Prototype模式是一種對象創建型模式,它采取復制原型對象的方法來創建對象的實例。使用Prototype模式創建的實例,具有與原型一樣的數據。 1)由原型對象自身創建目標對象。也就是說,對象創建這一動作發自原型對象本身。 2)目標對象是原型對象的一個克隆。也就是說,通過Prototype模式創建的對象,不僅僅與原型對象具有相同的結構,還與原型對象具有相同的值。 3)根據對象克隆深度層次的不同,有淺度克隆與深度克隆。
適用情況: 一個復雜對象,具有自我復制功能,統一一套接口。 對於對象比較復雜,每創建一次new 都會浪費好多的資源和時間 且在初始化的信息不發生變化的前提下 克隆是最好的辦法,
二:動機
在軟件系統中,經常面臨著“某些結構復雜的對象”的創建工作;由於需求的變化,這些對象經常面臨著劇烈的變化,但是他們卻擁有著比較穩定一致的接口。
如何應對這種變化?如何向“客戶程序(使用這些對象的程序)”隔離出“這些易變對象”,從而使得“依賴這些易變對象的客戶程序”不隨著需求改變而改變?
原型模式也是屬於對象創建模式,它用來處理某些結構復雜對象的創建工作,這也是與工廠模式最大的區別。
如果我們要創建的對象比較簡單的話,使用工廠模式new一下就可以了,但是當對象比較復雜,它的初始狀態不是我們最想用的時候,我們可以調用拷貝構造函數來深拷貝某個比較符合我們要求的對象。當然所謂的復雜是相對而言的,應當根據實際情況確定。
三:代碼講解
(一)原代碼
//抽象類 class ISplitter{ public: virtual void split()=0; virtual ~ISplitter(){} }; //工廠基類 class SplitterFactory{ public: virtual ISplitter* CreateSplitter()=0; virtual ~SplitterFactory(){} };
//具體類 class BinarySplitter : public具體類和具體工廠ISplitter{ }; class TxtSplitter: public ISplitter{ }; class PictureSplitter: public ISplitter{ }; class VideoSplitter: public ISplitter{ }; //具體工廠 class BinarySplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new BinarySplitter(); } }; class TxtSplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new TxtSplitter(); } }; class PictureSplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new PictureSplitter(); } }; class VideoSplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new VideoSplitter(); } };
(二)原型模式處理:將兩個類合並
1.將抽象類和抽象工廠合並
//抽象類 class ISplitter{ public: virtual void split()=0; //通過克隆自己來創建對象 virtual ISplitter* clone()=0; //CreateSplitter virtual ~ISplitter(){} };
2.將具體類和具體工廠合並
class BinarySplitter : public ISplitter{ //由原來的具體類和具體工廠合並 public: virtual ISplitter* clone(){ return new BinarySplitter(*this); //深拷貝,將原有狀態一並拷貝過去 } };
class TxtSplitter: public ISplitter{ public: virtual ISplitter* clone(){ return new TxtSplitter(*this); } }; class PictureSplitter: public ISplitter{ public: virtual ISplitter* clone(){ return new PictureSplitter(*this); } }; class VideoSplitter: public ISplitter{ public: virtual ISplitter* clone(){ return new VideoSplitter(*this); } };
(三)MainForm中使用
class MainForm : public Form { Isplitter* prototype;//原型對象 public: MainForm(Isplitter* prototype){ this->prototype=prototype; } void Button1_Click(){ //prototype->split; 不能直接使用,原型對象是專門供你克隆的,真正使用的時候,我們要使用新的對象 ISplitter * splitter= prototype->clone(); //克隆原型 splitter->split(); } };
四:模式定義
使用原型實例指定創建對象的種類,然後通過拷貝這些原型來創建新的對象。
--《設計模式》Gof
五:類圖(結構)
六:使用場景:和工廠相比
(一)當某一個對象比較復雜的時候,通常你發現他的初始狀態不是最理想的,這時候有一個對象,他的狀態已經達到比較好的狀態的時候,我們調用一下拷貝構造函數(深克隆),將他的狀態取出來,這樣就達到了一個比較好的狀態。
(二)而我們使用工廠模式,我們創建一個新的對象,當對象結構復雜,我們new一個新的對象後,往往需要大量的操作去達到一個較好的狀態,不夠靈活,所以工廠模式適用於結構不太復雜的對象。
(三)二者區別在於是否有較復雜的中間狀態,而且是否希望保留某個狀態
(四)一個復雜對象,具有自我復制功能,統一一套接口
七:要點總結
(一)Prototype模式同樣用於隔離類對象的使用者和具體類型(易變類)直接的耦合關系,他同樣要求這些“易變類”擁有“穩定的接口”。
(二)Prototype模式對於“如何創建易變類的實體對象”采用“原型克隆”的方法來做,它使得我們可以非常靈活地“動態創建”擁有某些穩定接口的新對象——所需工作僅僅是註冊一個新類的對象(即原型),然後在任何需要的地方clone。
(三)Prototype模式中的Clone方法可以利用某些框架中的序列化來實現深拷貝。
像python中pickle
八:案例實現
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <stdlib.h> #include <string> //需要加上string,不然cout<<string對象會報錯 using namespace std; class Programmer { public: virtual Programmer* clone() = 0; //接口 virtual void printInfo() = 0; virtual void setJob(char *job) = 0; virtual ~Programmer(){} }; class JavaProgrammer :public Programmer { private: string name; int age; char* job; public: JavaProgrammer(string name, int age) { this->name = name; this->age = age; job = NULL; } virtual void setJob(char *job) { this->job = new char[strlen(job) + 1]; strcpy(this->job, job); } virtual void printInfo() { cout << this->name << "\t" << this->age << endl; if (this->job) cout << this->job << endl; } virtual Programmer* clone() { Programmer* p = new JavaProgrammer(*this); //對其中指針,只是賦值,指向同一塊空間 p->setJob(this->job); //註意這一步,要做到深拷貝 return p; } virtual ~JavaProgrammer() { if (this->job!=NULL) { delete[] this->job; this->job = NULL; } } }; void main() { JavaProgrammer jv1("Mark", 20); jv1.setJob("java programmer"); jv1.printInfo(); Programmer* np = jv1.clone(); np->printInfo(); delete np; //保錯是因為拷貝問題 system("pause"); return; }
模擬狀態,我們不對原型對象進行修改
設計模式---對象創建模式之原型模式(prototype)