第3節 模板方法模式

一、模式分類

1. 從目的來看

1.1 創建型模式:指創建對象的模式,抽象勒實例化的過程,幫助系統獨立於如何創建愛你、組合和表示;
1.2 結構型模式:爲解決怎樣組裝現有類,設計他們的交互方式,而達到一定的功能;
1.3 行爲型模式:在不同對象之間劃分責任和算法的抽象化,重點關注它們是如何相互租用;

三者的關係

1) 創建模式爲其它兩種模式的使用提供環境,好比Visual Studio軟件提供了.NET的環境和 操作平臺,使各種語言能夠隨心所欲地在平臺上編譯執行;
2) 結構型模式側重於接口的使用,它做的一切工作都是對象或類之間的交互,提供一個門,成就一個你來我往、協同合作的地球村;
3) 行爲模型,顧名思義,側重於具體行爲,所以概念中才會出現職責分類和算法通信等內容.
將三者結合起來稱爲故事——中美合作的故事,其中:創建型模式提供國際環境,無戰爭、求發展;結構型模式爲中美合作提供理由,即和平時代的互利共贏; 行爲模式就具體到兩個大國之間是如何合作,比如經濟合作、文化合作等.

2. 從範圍來看

2.1 類模式處理類與子對象的靜態關係;
2.2 對象模式處理對象間的動態關係;

二、從封裝變化角度對模式分類

  • 組件寫作: 模板模式、策略模式、觀察者(事件)模式
  • 單一職責: 裝飾者模式、橋模式
  • 對象創建: 工廠模式、抽象模式、原型模式、構建者模式
  • 對象性能: 單例模式、Flyweight
  • 接口隔離: 外觀模式、代理模式、中介者模式、適配器模式
  • 狀態變化: 備忘錄模式、狀態模式
  • 數據結構: 複合模式、迭代器模式、職責鏈模式
  • 行爲變化: 命令模式、觀察者模式
  • 領域問題: 解釋器模式

三、重構獲得模式

  1. OOP設計模式是"好的OOP對象設計",所謂好的OOP對象設計,指可應對變化,提高複用率;
  2. 現代軟件設計的特徵是"需求的頻繁變化",設計模式的目標是"尋找變化點",然後在變化點處應用設計模式設計模式的難點在於"知道when,where使用設計模式",而不是看懂別人的設計模式代碼,或者生搬硬套設計模式;
  3. 設計模式不宜先入爲主,不應一遇到問題就套用設計模式,這可能導致模式的誤用,設計模式是逐漸迭代出來的;

四、推薦書籍

  • 《重構—改善既有代碼的設計》
  • 《重構與模式》

五、重構關鍵技法

靜態->動態 早綁定->晚綁定 繼承->組合 編譯時依賴->運行時依賴 緊耦合->松耦合

六、template設計模式

1.template模式設計動機

1.1 在軟件構建中,對於某些任務常有穩定的整體結構,但各子步驟確有很多改變的需求,或者由於固有的原因而無法與任務的整體結構同時實現
1.2 如何在確定穩定操作結構的前提下,來靈活應對各個子步驟的變化或者晚期實現需求?

2. 程序示例

很多時候,項目代碼中需要我們把些許凋以某種流程串聯起來.

#include <stdio.h>

// 1. 程序庫的開發人員(先開發)
class Library {
public:
    Library()  {}
    ~Library() {}
public: 
    void Step1(){
	// 完成某一項任務的幾個步驟,步驟1...
    }
    void Step3(){
	// 完成某一項任務的幾個步驟,步驟3...
    }
    void Step5(){
	// 完成某一項任務的幾個步驟,步驟5...
    }
};

// 2. 應用程序開發人員(後開發)
class Application
{
public:
    Application() {}
    ~Application(){}
public:
    bool Setp2() { return false; }
    void Step4()  {}
private:
};

// 3. 主函數中按照特有的流程將功能組合起來
int main()
{
    Library lib;
    Application app;
    lib.Step1();                               // 第一步

    if (app.Setp2())  lib.Step3();             // 第二步、第三步
    for (int i = 0; i < 4; i++) app.Step4();   // 第四步
    lib.Step5();                               // 第五步

    return 0;
}

3. 使用模板方法模式重構

#include <stdio.h>

// 1. 程序庫的開發人員(先開發)
class Library
{
public:
    Library()  {}
    // C++ 良好習慣:父類的析構函數都寫成虛的
    virtual ~Library() {}                   // 虛析構函數:刪除父對象時,子對象也刪除,不寫成虛析構函數則子類對象不能析構
protected:
    void Step1() {}
    void Step3() {}
    void Step5() {}
protected:
    virtual bool Step2() = 0;               // 虛函數,作用多態時,調用子類方法
    virtual void Step4() = 0;
public:
    // 穩定的template method
    void Run()
    {
	Step1();
	if (Step2())  Step3();
	for (int i = 0; i < 4; i++) Step4();
	Step5();
    }
};

//  2. 應用程序開發人員(後開發)
class Application:public Library
{
public:
    Application()  {}
    ~Application() {}
protected:
    virtual bool Step2(){
	// 子類開發人員重寫
	return false;
    }
    virtual void Step4() {
	// 子類開發人員重寫
    }
};

// 3. 主函數中按照特有的流程將功能組合起來
int main()
{
    Library *lib = new Application();
    lib->Run();
    delete lib; 

    return 0;
}

4. 重構分析

  • 重構前代碼: Application(開發完)調用Library(開發早),稱爲早綁定
  • 重構後代碼: Library(開發早)調用Applicaiton(開發晚),稱爲晚綁定

模板模式總結:

  • 即早期定義骨架(穩定),支持細節(變化)延遲在子類中定義,即可提高父類的複用,並且子類可以重新定義細節;
  • 穩定的代碼使用實函數,可變的寫成虛函數,前提條件是父類有一個穩定的構架,不然則不適合模板模式;
  • 啓發:模板模式給我們的啓示就是做項目的時候一定要學會分析代碼中哪些是穩定的,哪些部分不是穩定的;

5. 要點總結

  1. Template Method是一種非常基礎性的設計模式,在OOP對象系統中有大量的應用。它用最簡潔的機制(虛函數多臺),爲很多App提供了靈活的擴展點,是代碼複用的基本實現結構;
  2. 除了靈活應對子步驟的變換外,"不要調用我,讓我來調用你"的反向控制結構是模板模式的電影應用;
  3. 具體實現上,被模板模式調用的虛方法可以具有實現,也可以沒有任何實現(抽象方法、純虛方法),但一般推薦將他們設置爲protected方法.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章