prototype模式經過實例對象指定須要建立的類型,這與上一篇咱們提到的factory method模式有本質不一樣,factory method模式是經過類的繼承定義不一樣子類來達到建立不一樣類型對象的目的,屬於類模式,prototype模式經過調用組合的對象成員生成不一樣類型的對象實例,屬於對象模式。html
因爲這個特性,prototype具備如下適用場合:ios
· 須要運行時肯定實例化的類時,好比動態裝載庫時c++
· 避免建立過多子類時。子類太多永遠是不受歡迎的,在factory method中咱們也提到經過模板或者參數化來減小子類數目。函數
· 實例化對象的狀態組合過多時,先創建原型庫,使用時經過註冊表取得相應原型來生成目標對象會更加方便。this
prototype的優勢包括:spa
· 運行時增長和刪除產品prototype
· 改變對象,這點是組合模式的共同優勢設計
· 減小子類的數目指針
· 用類動態配置應用code
prototype的最大缺點應該就是在某些語言中實現clone操做可能會很困難,特別是包含循環引用的額狀況下。
下面繼續使用上一篇文章中的例子,開發一個芯片設計軟件,用prototype實現。全部的圖形繼承自MaskFigure,必須實現clone函數,MaskDesigner初始化時傳入對象原型指針,MakeFigure時經過原型的clone生成新的圖形。Factory method是經過圖形對應的類調用圖形類的構造函數生成新的對象,通俗點講,就好像factory method是用設計圖紙從新畫了個圖形出來,而prototype是臨摹已經畫好了的圖形。類結構以下:
代碼實現以下:
//mask.hpp #ifndef MASK_HPP #define MASK_HPP class MaskFigure{ public: virtual ~MaskFigure()=0; virtual MaskFigure* clone()=0; protected: MaskFigure(); MaskFigure(const MaskFigure&); }; class MaskRound:public MaskFigure { public: MaskRound(); MaskRound(const MaskRound&); MaskRound* clone(); ~MaskRound(); }; class MaskRec:public MaskFigure { public: MaskRec(); MaskRec(const MaskRec&); MaskRec* clone(); ~MaskRec(); }; class MaskTri:public MaskFigure { public: MaskTri(); MaskTri(const MaskTri&); MaskTri* clone(); ~MaskTri(); }; #endif //mask.cpp #include <iostream> #include "mask.hpp" using std::cout; using std::endl; MaskFigure::MaskFigure() { cout<<"init MaskFigure"<<endl; } MaskFigure::MaskFigure(const MaskFigure& mf) { cout<<"copy Figure"<<endl; } MaskFigure::~MaskFigure() { cout<<"delete MaskFigure"<<endl; } MaskRound::MaskRound() { cout<<"Draw roundness on Mask"<<endl; } MaskRound::MaskRound(const MaskRound& mr) :MaskFigure(mr){ cout<<"copy roundness"<<endl; } MaskRound* MaskRound::clone() { return new MaskRound(*this); } MaskRound::~MaskRound() { cout<<"delete MaskRound"<<endl; } MaskRec::MaskRec() { cout<<"Draw rectangle on Mask"<<endl; } MaskRec::MaskRec(const MaskRec& mr) :MaskFigure(mr){ cout<<"copy rectangle"<<endl; } MaskRec* MaskRec::clone() { return new MaskRec(*this); } MaskRec::~MaskRec() { cout<<"delete MaskRec"<<endl; } MaskTri::MaskTri() { cout<<"Draw triangle on Mask"<<endl; } MaskTri::MaskTri(const MaskTri& mt) :MaskFigure(mt){ cout<<"copy triangle"<<endl; } MaskTri* MaskTri::clone() { return new MaskTri(*this); } MaskTri::~MaskTri() { cout<<"delete MaskTri"<<endl; } //maskdesigner.hpp #ifndef FIGUREDESIGNER_HPP #define FIGUREDESIGNER_HPP #include "mask.hpp" class FigureDesigner{ public: FigureDesigner(MaskFigure *mf){ figure = mf; } MaskFigure* MakeFigure(){ return figure->clone(); } private: MaskFigure *figure; }; #endif //main.cc #include <memory> #include <iostream> #include "maskdesigner.hpp" using std::cout; using std::endl; using std::shared_ptr; int main() { MaskRound mro; MaskRec mre; MaskTri mtr; FigureDesigner md1(&mro); shared_ptr<MaskFigure> mfptr1(md1.MakeFigure()); FigureDesigner md2(&mre); shared_ptr<MaskFigure> mfptr2(md2.MakeFigure()); FigureDesigner md3(&mtr); shared_ptr<MaskFigure> mfptr3(md3.MakeFigure()); }
講到prototype模式,有必要提一下c++ Covariance特性,即c++的協變性質,在虛函數實現時,通常要求派生類重寫的虛函數必須與基類函數有一致的返回值類型,參數個數及類型。
不過這也有個特例,若是返回值類型知足下面條件時能夠不一樣,
1. 基類和派生類虛函數返回值類型都是指向類的指針或者引用
2. 基類虛函數返回值指針或引用所指向的類類型是派生類返回值指針或引用所指向的類類型的間接或直接基類,即屬於同一個繼承體系。
這表示以下狀況是容許的,
class Base { /* ... */ }; class Derived: public Base { /* ... */ }; class B { virtual Base* func() { return new Base; } virtual ~B() { } }; class D: public B { Derived* func() { return new Derived; } virtual ~D() { } };
fanc的返回值分別是base*和Derived*,屬於同一繼承體系內。但返回值換成其餘類型如基本類型時則不容許。這一特性在prototype中獲得充分的應用, MaskFigure的clone函數返回 MaskFigure*指針類型,MaskRound,MaskRec和MaskTri的clone函數分別返回MaskRound*,MaskRec*和MaskTri*指針類型。
(完)