C 設計模式 Template Method

2021-07-28 11:27:34 字數 3816 閱讀 8186

我使用過乙個簡單的後台服務框架.這個框架上手很容易,我只需要繼承乙個基類,同時實現,或重寫(override)基類宣告的幾個介面(這些介面宣告為虛函式,或者純虛函式),然後呼叫基類定義好的run()函式,便可以將框架**執行起來.run函式做的事情,是依序呼叫上述的幾個介面:

class service 

protected:

virtual int step1()

virtual int step3()

virtual int step4()

virtual int step2() =0 ; //純虛函式,派生類實現

}

其中收包,解包,回包,釋放資源等動作,框架會提供乙份實現,由於我們有時候會採用其他的資料協議,所以基類也將收包回包等函式宣告為虛函式,允許我們針對新的協議進行函式的重寫(override).而對於業務邏輯處理函式,也就是step2,框架無法為我們實現,我們需要根據具體的業務需求來實現該函式,在派生類中來實現step2函式:

class myservice : public service

}

派生類實現了step2函式後,通過呼叫run函式來執行程式:

void main ()

// ...

}

我們的後台服務框架例子中,run函式定義了乙個服務的穩定執行步驟,但某個步驟有著特定的需求無法馬上定義,需要延遲到派生類中去實現,這時候就需要採用模板方法模式.模板方法模式要解決的問題是:如何在確定穩定操作結構的前提下,靈活地應對各個子步驟的變化或者晚期實現需求?李建忠老師曾提過,重構獲得設計模式(refactoring to patterns).設計模式的應用不宜先入為主,一上來就使用設計模式是對設計模式的最大誤用,在敏捷軟體開發中,提倡使用的是通過重構來獲得設計模式,這也是最好的使用設計模式的方法.

而關於重構的關鍵技法,包括了:

接下來我們來看看如何將乙個程式,重構成模板方法模式.現代軟體專業分工之後,也出現了"框架與應用程式的劃分",框架實現人員先定義好框架的執行流程,也就是演算法骨架(穩定),並提供可重寫(overide)的介面(變化)給應用開發人員,以開發適應其應用程式的子步驟.模板方法通過晚繫結,實現了框架與應用程式之間的松耦合.

現在我們需要實現乙個程式庫,需要四個步驟來完成相應功能.其中step1,step3步驟穩定,而step2,step4則根據不同應用的具體需要,自行定義其具體功能,庫開發人員無法預先實現好step2,step4.那麼庫開發人員可以先寫好:

// 庫開發人員

class library

void step3()

應用程式開發人員則根據具體的應用需求,來實現剩餘的兩個步驟:

//應用程式開發人員

public:

void step2()

bool step4()

}

然後應用程式開發人員還需要寫乙個main方法,將步驟以某種流程串起來:

//穩定

public static void main(string args)

}

這種辦法實際上是一種c語言結構化的實現方式,雖然用的是c++,但沒有體現出物件導向的特性來.main方法中,四個步驟的呼叫過程是相對穩定的,我們可以把這種穩定提公升到庫的實現中去,而應用程式開發人員,只需要實現"變化"的**即可.這就引出了第二種做法.

第二種做法,是庫開發人員不僅實現step1(),step3(),同時將step2(),step4()宣告為純虛函式,等待應用程式開發人員自己去實現這兩個純虛函式.注意到,main方法中定義的執行流程是相對穩定的,完全可以把這些步驟移動到庫類中去.

//庫開發人員

class library

step4(); //支援變化-->虛函式的多型呼叫

}

protected:

void step1()

void step3()

virtual bool step2() =0; //純虛函式

virtual void step4() = 0; //純虛函式

virtual ~library()

};

注意step2,step4為純虛函式,這是因為庫開發人員無法知道怎麼寫,留給程式庫開發人員來實現,也就是"把實現延遲",這在c++中體現為虛函式或純虛函式,由應用程式開發人員繼承library以實現兩個純虛函式.這一段**實際上體現了大部分設計模式應用的特點,也就是在穩定中包含著變化,run函式的演算法流程是穩定的,但是演算法的某個步驟是可變的,可變的延遲實現:

protected:

virtual bool step2()

virtual void step4()};

然後,應用程式開發人員,只需要通過多型指標來完成框架的使用:

public static void main(string args)
回顧兩種實現方式,我們可以發現,第一種實現方式中:

採用了模板方法模式的實現方式中:

一般來說,框架/元件/庫的實現,總是要先於應用程式的開發的.在第一種方式中,應用程式開發者(晚開發)的執行流程呼叫了庫開發者定義好的函式(早開發),稱為早繫結,而反過來在模板方法模式中,庫開發者在執行流程中先呼叫了step2,step4函式,而這兩個函式需要延遲到應用程式開發人員真正實現時,才通過虛函式機制進行呼叫,這種方式則稱為早繫結.這便是重構使用設計模式的技法: 早繫結->晚繫結.

回過頭來看看模板方法模式的定義:定義乙個操作中的演算法的骨架,而將一些步驟延遲到子類中.template method使得子類刻意不改變乙個演算法的結構即可重定義該演算法的某些特定步驟.(《設計模式》 gof)所謂的骨架,要求是相對穩定的,在上面的例子中,如果step1,step3也是不穩定的,那麼該情景下就不適用於適用設計模式,原因是軟體體系中所有的東西都不穩定.設計模式的假設條件是必須有乙個穩定點,如果沒有穩定點,那麼設計模式沒有任何作用.反過來說,如果所有的步驟都是穩定的,這種極端情況也不適用於適用設計模式.設計模式總是處理"穩定中的變化"這種情景.設計模式最大的作用,是在穩定與變化之間尋找隔離點,然後來分離它們,從而來管理變化.從而我們也能夠得到啟發,學會分析出軟體體系結構中哪部分是穩定的,哪部分是變化的,是學好設計模式的關鍵點.

再來看一看模板方法設計模式的結構:其中templatemethod() 方法也就是我們上面所說的run函式,它相對穩定,primitiveoperation1(),primitiveoperation2()為兩個變化的函式,可由派生類實現,在templatemethod()中呼叫步驟.在下圖中,紅色圈為穩定的部分,而黑色圈為變化的部分.

在物件導向的時代,絕大多數的框架設計都使用了模板方法模式.作為乙個應用程式開發人員,我們往往只需要實現幾個步驟,框架便會把我們的步驟"串接"到執行流程中,有時候甚至連main函式都不用我們去實現.這樣子也有弊端,我們看不見框架的執行流程,執行細節是怎麼樣的,往往有一種"只見樹木不見森林"的感覺.

最後來總結以下模板方法設計模式.template method設計模式是一種非常基礎性的設計模式,它要解決的問題是如何在確定穩定操作結構的前提下,來靈活應對各個子步驟的變化或者晚期實現需求.它使用了函式的多型性機制,為應用程式框架提供了靈活的拓展點,是**復用方面的基本實現結構.template method設計模式明顯劃分了穩定與變化的關係,除了靈活應對子步驟的變化外,也是晚繫結的典型應用,通過反向控制結構,使得早期的**可以呼叫晚期**.而在具體實現上,被template method呼叫的虛函式,可以具有實現,也可以沒有任何實現,這在c++中體現為虛函式或者純虛函式,一般將這些函式設定為proteced方法.

C設計模式,C 設計模式解說文件

個人引用了知乎上面一位的回答 遂感覺暫時沒有接觸設計模式的必要,於是將手頭上的資源寫成部落格權當收藏 學習設計模式的乙個弊端是 我們學習的時候看到的只是結果,並不了解過程和動機,也就是其他人在什麼樣的情況下做出這樣的設計,而這個恰恰是各種教程 資料上學習不到的。我自己在經歷了2年的應用設計模式的摸索...

C 設計模式

c 設計模式大體上講分為三類,即 建立模式,結構模式和行為模式 建立模式 單例模式 工廠模式 抽象工廠模式 生成器模式 原型模式。結構模式 介面卡模式 橋接模式 組成模式 裝飾模式 外觀模式 享元模式 模式。行為模式 中介者模式 命令模式 備忘錄模式 狀態模式 策略模式 直譯器模式 迭代器模式 觀察...

C 設計模式

c 設計模式 課程目標 理解松耦合設計思想 掌握物件導向設計原則 掌握重構技法改善設計 掌握gof 核心設計模式 什麼事設計模式 每乙個模式描述了乙個在我們周圍不斷重 生的問題以及該問題的解決方案的核心。這樣,你就能一次又一次的 使用該方案而不必做重複勞動 gof設計模式 歷史性著作 設計模式 可復...