面向對象的可復用設計模式之模板方法模式(24/24)

小智雅匯 發佈 2020-02-22T23:42:03+00:00

3總結重複=易錯+難改,模板方法模式是通過父類建立框架,子類在重寫了父類部分方法之後,在調用從父類繼承的方法,產生不同的效果,通過修改子類,影響父類行為的結果,模板方法在一些開源框架中應用非常多,它提供了一個抽象類,然後開源框架寫了一堆子類,如果需要擴展功能,可以繼承此抽象類,然

模板方法模式(Template pattern)是指在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中的某些步驟。

模板方法屬於行為型設計模式,行為型設計模式主要關注對象之間職責分配和算法的問題。類行為型模式使用繼承來分配類之間的職責,模板方法就是個類行為型模式。對象行為型模式使用組合來分配職責。在我們構建軟體的過程中大部分時候我們都是在思考實體之間的職責,怎樣的職責分配最合理,不至於過重,又不至於過輕,而且又不越權。

模板方法模式在一個方法中定義一個算法的骨架,而將一些步驟的實現延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中某些步驟的具體實現。

看到「設計模式」這四個字我們往往會覺得高深莫測,但是模板方法模式卻是一個例外,你要關注的就是一個方法而已。

模板方法模式確實非常簡單,僅僅使用繼承機制,但是它是一個應用非常廣泛的模式。

AbstractClass(抽象類):定義抽象的原語操作,具體的子類將重定義它們以實現一個算法的各步驟。主要是實現一個模板方法,定義一個算法的骨架。該模板方法不僅調用原語操作,也調用定義在AbstractClass或其他對象中的操作。

ConcreteClass(具體類):實現原語操作以完成算法中與特定子類相關的步驟。

由於在具體的子類ConcreteClass中重定義了實現一個算法的各步驟,而對於不變的算法流程則在AbstractClass的TemplateMethod中完成。

#include <iostream>
using namespace std;

class AbstractClass
{
public:
     void TemplateMethod()
     {
          PrimitiveOperation1();
          cout<<"TemplateMethod"<<endl;
          PrimitiveOperation2();
     }

protected:
     virtual void PrimitiveOperation1()
     {
          cout<<"Default Operation1"<<endl;
     }

     virtual void PrimitiveOperation2()
     {
          cout<<"Default Operation2"<<endl;
     }
};

class ConcreteClassA : public AbstractClass
{
protected:
          virtual void PrimitiveOperation1()
     {
          cout<<"ConcreteA Operation1"<<endl;
     }

     virtual void PrimitiveOperation2()
     {
          cout<<"ConcreteA Operation2"<<endl;
     }
};

class ConcreteClassB : public AbstractClass
{
protected:
          virtual void PrimitiveOperation1()
     {
          cout<<"ConcreteB Operation1"<<endl;
     }

     virtual void PrimitiveOperation2()
     {
          cout<<"ConcreteB Operation2"<<endl;
     }
};

int main()
{
     AbstractClass *pAbstractA = new ConcreteClassA;
     pAbstractA->TemplateMethod();

     AbstractClass *pAbstractB = new ConcreteClassB;
     pAbstractB->TemplateMethod();

     if (pAbstractA) delete pAbstractA;
     if (pAbstractB) delete pAbstractB;
}
/*
output:

ConcreteA Operation1
TemplateMethod
ConcreteA Operation2
ConcreteB Operation1
TemplateMethod
ConcreteB Operation2 
*/


1 模板方法模式的使用場景

模板方法是一種代碼復用的基本技術。它們在類庫中尤為重要,它們提取了類庫中的公共行為。在使用模板方法時,很重要的一點是模板方法應該指明哪些操作是可以被重定義的,以及哪些是必須被重定義的。要有效的重用一個抽象類,子類編寫者必須明確了解哪些操作是設計為有待重定義的。

當系統中算法的骨架是固定的時候,而算法的實現可能有很多種的時候,就需要使用模板方法模式。

1.1 多個子類有共有的方法,並且邏輯基本相同。

1.2 重要、複雜的算法,可以把核心算法設計為模板方法,周邊的相關細節功能則由各個子類實現。

1.3 重構時,模板方法是一個經常使用的方法,把相同的代碼抽取到父類中,然後通過構造函數約束其行為。

例如需要做一個報表列印程序,用戶規定需要表頭、正文、表尾。但是客戶的需求會變化,一會希望這樣顯示表頭,一會希望那樣顯示,這時候採用模板方式就合適。

2 模板方法模式的優缺點

2.1 優點

2.1.1 封裝不變部分,擴展可變部分。把認為不變部分的算法封裝到父類中實現,而可變部分的則可以通過繼承來繼續擴展。

2.1.2 提取公共部分代碼,便於維護。

2.1.3 行為由父類控制,子類實現。

2.2 缺點

2.2.1 算法骨架需要改變時需要修改抽象類。

2.2.2 按照設計習慣,抽象類負責聲明最抽象、最一般的事物屬性和方法,實現類負責完成具體的事務屬性和方法,但是模板方式正好相反,子類執行的結果影響了父類的結果,會增加代碼閱讀的難度。

3 總結

重複=易錯+難改,模板方法模式是通過父類建立框架,子類在重寫了父類部分方法之後,在調用從父類繼承的方法,產生不同的效果,通過修改子類,影響父類行為的結果,模板方法在一些開源框架中應用非常多,它提供了一個抽象類,然後開源框架寫了一堆子類,如果需要擴展功能,可以繼承此抽象類,然後覆寫protected基本方法,然後在調用一個類似TemplateMethod()的模板方法,完成擴展開發。

-End-

關鍵字: