設計模式一直是面向對象軟件設計中最重要的一個領域,圍繞設計模式討論的話題也是數不勝數,其中GOF表明的23種設計模式更是經典之著。這個系列中我將會從本身的理解出發,闡述每種設計模式的思想,做用和利弊。ios
1、 設計模式概念c++
要講解設計模式,必然先要說清楚兩個問題,算法
1.什麼是設計模式?設計模式
2.爲何須要設計模式?函數
對於設計模式,GOF是這麼定義的:設計模式是對被用來在特定場景下解決通常設計問題的類和相互通訊的對象的描述,更特殊地,將之放到面向對象軟件設計中來說,設計模式能夠被認爲是實踐中總結出的設計經驗,是系統中會重複出現的設計。ui
因此設計模式能夠幫助咱們更加簡單方便地複用成功的設計和體系結構,更具體地,爲了得到最大限度地複用的關鍵在於新需求和已有需求發生變化時,系統設計有能力相應地改進,避免從新設計帶來的巨大代價。每種設計模式都是經過確保系統以某種特定方式變化來得到這種可變能力,每個設計模式容許系統結構的某個方面獨立於其餘方面,從而對某一種特殊變化具備適應性。spa
這就引出了選擇設計模式的方法:首先考慮系統在哪些方面具備可變性,選擇的設計模式不會由於這些可變因素而引發從新設計。GOF根據設計模式完成的任務類型將其分爲了建立型,結構型和行爲型三大類,建立型模式用於對象的建立,結構型模式用於處理類或者對象的組合;行爲型模式描述類或對象怎樣交互和分配職責。同時根據範圍模式分爲類模式和對象模式,類模式處理類和子類之間的關係,經過繼承建立,是靜態的,編譯期就肯定了;對象模式處理對象之間的關係,是動態的,運行時可變,具體分類如表格所示:prototype
|
建立型設計 |
結構型代理 |
行爲型 |
類模式 |
Factory method |
Adapter |
Interpreter template method |
對象模式 |
Abstract factory builder prototype singleton |
Adapter bridge composite decorator facade flyweight proxy |
Chain of responsibility command iterator mediator memento observer state strategy visitor |
建立型類模式將對象的部分建立工做延遲到子類,建立型對象模式則延遲到另外一個對象中。結構型類模式使用繼承機制來組合類,結構型對象模式則描述了對象的組合方式。行爲類模式用繼承描述算法和控制流,行爲型對象模式則經過一組對象協做完成任務。另外咱們將會看到,在部分類模式中,經過引入參數或者模板類型能夠避免建立子類。
本系列以建立型模式的factory method模式開始,逐個介紹GOF的23種設計模式。
2、 factory method模式
若是一個類不知道須要建立的對象的類型時,若是當前但願子類來指定建立的對象類型時,若是但願將建立對象的職責委託給子類並將這一代理過程局部化時,就能夠考慮使用factory method模式。
下面以一個例子來講明,這個例子也會在後續設計模式中屢次提到,因此請讀者先記住一下。如今要開發一個芯片設計的軟件,能夠在掩模上設計不一樣的圖形。不一樣的掩模會有不一樣的參數,好比曝光方式,角度等,圖形也能夠會有不少種,在不影響理解的前提下咱們假設只有圓形,矩形和三角形三種圖形,在不一樣的掩模上畫同一個圖獲得的效果是不同的。對於同一種掩模,咱們要獲得一個能夠畫圖的對象,至於畫出的是圓形,矩形仍是三角形,子類才能知道,掩模只能拿到接口。類設計圖以下:
具體代碼實現以下:
//mask.hpp #ifndef MASK_HPP #define MASK_HPP class MaskFigure{ public: virtual ~MaskFigure()=0; protected: MaskFigure(); }; class MaskRound:public MaskFigure { public: MaskRound(); ~MaskRound(); }; class MaskRec:public MaskFigure { public: MaskRec(); ~MaskRec(); }; class MaskTri:public MaskFigure { public: MaskTri(); ~MaskTri(); }; #endif //mask.cpp #include <iostream> #include "mask.hpp" using std::cout; using std::endl; MaskFigure::MaskFigure() { } MaskFigure::~MaskFigure() { } MaskRound::MaskRound() { cout<<"Draw roundness on Mask"<<endl; } MaskRound::~MaskRound() { } MaskRec::MaskRec() { cout<<"Draw rectangle on Mask"<<endl; } MaskRec::~MaskRec() { } MaskTri::MaskTri() { cout<<"Draw triangle on Mask"<<endl; } MaskTri::~MaskTri() { } //factory.hpp #ifndef MASKFACTORY_HPP #define MASKFACTORY_HPP #include "mask.hpp" class FigureFactory { public: virtual ~FigureFactory()=0; virtual MaskFigure* CreateFigure()=0; protected: FigureFactory(); }; class RoundFactory:public FigureFactory { public: RoundFactory(); ~RoundFactory(); MaskRound* CreateFigure(); }; class RecFactory:public FigureFactory { public: RecFactory(); ~RecFactory(); MaskRec* CreateFigure(); }; class TriFactory:public FigureFactory { public: TriFactory(); ~TriFactory(); MaskTri* CreateFigure(); }; #endif //factory.cpp #include <iostream> #include "factory.hpp" using std::cout; using std::endl; FigureFactory::FigureFactory() { } FigureFactory::~FigureFactory() { } RoundFactory::RoundFactory() { cout<<"Init RoundFactory"<<endl; } RoundFactory::~RoundFactory() { } MaskRound* RoundFactory::CreateFigure() { return new MaskRound(); } RecFactory::RecFactory() { cout<<"Init RecFactory"<<endl; } RecFactory::~RecFactory() { } MaskRec* RecFactory::CreateFigure() { return new MaskRec(); } TriFactory::TriFactory() { cout<<"Init TriFactory"<<endl; } TriFactory::~TriFactory() { } MaskTri* TriFactory::CreateFigure() { return new MaskTri(); } //main.cc #include <memory> #include <iostream> #include "factory.hpp" #include "factorytml.hpp" using std::shared_ptr; int main() { shared_ptr<RoundFactory> roundfac(new RoundFactory()); shared_ptr<MaskRound> mrd(roundfac->CreateFigure()); shared_ptr<RecFactory> recfac(new RecFactory()); shared_ptr<MaskRec> mrc(recfac->CreateFigure()); shared_ptr<TriFactory> trifac(new TriFactory()); shared_ptr<MaskTri> mti(trifac->CreateFigure()); return 0; }
roundness, rectangle和 triangle的構造都分別延遲到了 RoundFactory, RecFactory和TriFactory等派生類中完成,因此factory method模式又被成爲虛構造函數。
不難發現,MaskFigure有幾個子類, FigureFactory也須要對應數目的子類,MaskFigure增長一個圖形時,FigureFactory就必須增長相應的工廠方法,有時候會產生太多子類,不易維護,c++中能夠引入模板或者參數化來解決,從而避免建立子類。一個模板實現的factory method實例以下:
//factorytml.hpp #ifndef FACTORYTML_HPP #define FACTORYTML_HPP #include <iostream> using std::cout; using std::endl; class FigureFactoryTml { public: FigureFactoryTml(){ cout<<"Init FigureFactoryTml"<<endl; } ~FigureFactoryTml(){ } template<typename T> T* CreateFigure() { return new T(); } }; #endif //main.cc … shared_ptr<FigureFactoryTml> fft(new FigureFactoryTml()); shared_ptr<MaskRound> mrdp(fft->CreateFigure<MaskRound>()); shared_ptr<MaskRec> mrcp(fft->CreateFigure<MaskRec>()); shared_ptr<MaskTri> mtip(fft->CreateFigure<MaskTri>()); …
(完)