c++ 設計模式8 (Factory Method 工廠方法)
5. “對象創建”類模式
通過“對象創建”類模式繞開new,來避免對象創建(new)過程中所導致的緊耦合(依賴具體類),從而支持對象創建的穩定。它是接口抽象之後的第一步工作。
5.1 工廠方法
動機:
在軟件系統中,經常面臨著創建對象的工作;由於需求的變化,需要創建的對象的具體類型經常變化。
如何應對這種變化?如何繞過常規的對象創建方法(new),提供一種“封裝機制”來避免客戶程序和這種“具體對象創建工作”的緊耦合?
代碼示例:
仍然考慮文件分割器案例,不考慮與創建對象無關的代碼部分,暫時忽略內存管理,專註於工廠方法模式的應用。
在實現代碼1中,不同類型的文件分割器類(File,Pic,Video等)繼承文件分割器抽象基類。
在MainForm中,MainForm類依賴(編譯時依賴)了具體的類BinarySpitter,違背了依賴倒置原則。此時即出現了動機中說明的創建對象過程中導致的緊耦合。
采用工廠方法模式的解決方案見代碼2,考慮過程如下:
1.利用new方法創建的對象必須依賴於具體類,不可取;所以考慮創建一個類,利用其中方法的返回值作為創建對象的結果;
2.然而單純的返回一個具體類的對象仍然沒有解決依賴倒置的問題,所以考慮將該類設計為一個抽象類,具體的返回由其子類來確定。
3.依照上述思想創建工廠基類SplitterFactory(抽象類),具體工廠(BinarySplitterFactory等)返回具體的對象。
4.MainForm使用過程中,聲明一個工廠字段,在具體創建對象過程中采用統一的依賴於抽象的創建方法,即
ISplitter * splitter= factory->CreateSplitter(); //相當於多態new
而factory具體指向的對象類型由MainForm構造函數通過外界傳入。
註:可以從上述分析和代碼中看出,工廠方法模式的使用,並不是為了消除變化(事實上變化不可能消除),而是將變化排除在MainForm之外(類比將變化趕到一個小範圍),使其更加可控,從而使文件分割器的設計和使用滿足面向對象設計原則,在應對變化時表現出優勢。
1 //FileSpiltter1.cpp 2 class ISplitter{ 3 public: 4 virtual void split()=0; 5 virtual ~ISplitter(){} 6 }; 7 8 class BinarySplitter : public ISplitter{ 9 10 }; 11 12 class TxtSplitter: public ISplitter{ 13 14 }; 15 16 class PictureSplitter: public ISplitter{ 17 18 }; 19 20 class VideoSplitter: public ISplitter{ 21 22 }; 23 24 //MaiForm1.cpp 25 class MainForm : public Form 26 { 27 TextBox* txtFilePath; 28 TextBox* txtFileNumber; 29 ProgressBar* progressBar; 30 31 public: 32 void Button1_Click(){ 33 34 35 36 ISplitter * splitter= 37 new BinarySplitter();//依賴具體類 38 39 splitter->split(); 40 41 } 42 };
1 //ISpiltterFactory.cpp 2 3 //抽象類 4 class ISplitter{ 5 public: 6 virtual void split()=0; 7 virtual ~ISplitter(){} 8 }; 9 10 11 //工廠基類 12 class SplitterFactory{ 13 public: 14 virtual ISplitter* CreateSplitter()=0; 15 virtual ~SplitterFactory(){} 16 }; 17 18 //FileSpiltter2.cpp 19 20 //具體類 21 class BinarySplitter : public ISplitter{ 22 23 }; 24 25 class TxtSplitter: public ISplitter{ 26 27 }; 28 29 class PictureSplitter: public ISplitter{ 30 31 }; 32 33 class VideoSplitter: public ISplitter{ 34 35 }; 36 37 //具體工廠 38 class BinarySplitterFactory: public SplitterFactory{ 39 public: 40 virtual ISplitter* CreateSplitter(){ 41 return new BinarySplitter(); 42 } 43 }; 44 45 class TxtSplitterFactory: public SplitterFactory{ 46 public: 47 virtual ISplitter* CreateSplitter(){ 48 return new TxtSplitter(); 49 } 50 }; 51 52 class PictureSplitterFactory: public SplitterFactory{ 53 public: 54 virtual ISplitter* CreateSplitter(){ 55 return new PictureSplitter(); 56 } 57 }; 58 59 class VideoSplitterFactory: public SplitterFactory{ 60 public: 61 virtual ISplitter* CreateSplitter(){ 62 return new VideoSplitter(); 63 } 64 }; 65 66 //MainForm2.cpp 67 class MainForm : public Form 68 { 69 SplitterFactory* factory;//工廠 70 71 public: 72 73 MainForm(SplitterFactory* factory){ 74 this->factory=factory; 75 } 76 77 void Button1_Click(){ 78 79 80 ISplitter * splitter= 81 factory->CreateSplitter(); //多態new 82 83 splitter->split(); 84 85 } 86 };
模式定義:
定義一個用於創建對象的接口,讓子類決定實例化哪一個類,Factory Method使得一個類的實例化延遲(目的:解耦 ,手段:虛函數)到子類。
類圖:
總結:
Factory Method模式用於隔離類對象的使用者與具體類型之間的耦合關系。面對一個經常變化的具體類型,緊耦合關系(new)會導致軟件的脆弱。
Factory Method模式通過面向對象的手法,將所有創建的具體對象延遲到子類,從而實現一種擴展(而非更改)的策略,較好地解決了這種緊耦合關系。
Factory Method模式解決“單個對象”的需求變化。缺點在於要求創建方法/參數相同。
c++ 設計模式8 (Factory Method 工廠方法)