大衛的Design Patterns學習筆記22:Template Method

一、概述
Template Method(模板方法)模式定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
這裏所說的Template跟Generic Programming(範型編程)中討論的C++template不是一回事(雖然有一定的相似性),C++template是一種邏輯複用的方式,它可以不依賴於OO的Inheritance(繼承)機制獨立存在,因爲GP跟OO所討論的是完全不同的兩個方面,雖然二者經常被融合在一起使用;Template Method模式與template不同,它是建立在繼承機制 + 虛函數基礎上的,它的核心在於在基類中定義好邏輯處理的框架(或稱完成一項任務所需依次執行的步驟,或一段通用的處理邏輯),將具體的處理細節交給子類具體實現,從而達到“使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟”的目的。

二、結構
Template Method模式的結構如下圖所示:

1、Template Method模式類圖示意
其中的參與者比較簡單:
1.
AbstractClass(抽象類):定義一到多個抽象方法(也可以不是抽象方法,但至少應該是virtual方法。視你的應用需要,如果你的AbstractClass負責實現一個通用版本的算法,各子類對該方法進行進一步細化,則只需定義成virtual方法即可),具體的子類將重定義它們以實現一個算法;而且還實現一個模板方法,來定義一個算法的骨架。該模板方法不僅調用前面的抽象方法,也可以調用其他的操作。各抽象方法往往被定義成protected(保護)成員,以保證它們只被模板方法調用,而TemplateMethod往往被定義成public非虛成員函數。
2.
ConcreteClass(具體類):實現父類中的抽象方法以完成算法中與特定子類相關的步驟。
這裏的關鍵是基類中的TemplateMethod方法,因爲正是它定義了對各子類對象適用的通用的處理邏輯。

三、應用
Template Method模式是一個使用頻率比較高的模式,因爲對於同一種類型的對象而言,他們之間一些處理流程往往是一致的,對象之間的差異僅在於具體的處理邏輯,因此,可以將通用的邏輯提取出來放到AbstractClass中實現,而將實現的具體細節交給子類完成。
從這一點上講,Template Method與Strategy模式存在一定的相似性,但Template Method中實現的主體是ConcreteClass,AbstractClass僅定義了接口和希望子類重新定義的方法,通過繼承來改變算法;而Strategy模式中Context類與Strategy類之間不存在繼承關係,體現的是一種委託的關係。

四、優缺點

五、舉例
MFC作爲一個典型的應用程序框架,可以從中找到一些應用Template Method的例子,如:

void
 CView::OnPaint()    // Template Method
{
    // standard paint routine
    CPaintDC dc(this);
    OnPrepareDC(&dc);
    OnDraw(&dc);
}


void
 CView::OnDraw(CDC*)    // default implementation is empty, subclass always need override it.
{
}


void
 CView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)    // provide a basic implementation
{
    ASSERT_VALID(pDC);
    UNUSED(pDC); // unused in release builds

    // Default to one page printing if doc length not known
    if (pInfo != NULL)
        pInfo->m_bContinuePrinting =
            (
pInfo->GetMaxPage() != 0xffff || (pInfo->m_nCurPage == 1));
}


上面的OnPaint就有幾分Template Method模式的意思。
下面是一個運用Template Method進行排序的例子,基本的排序邏輯在基類Sort中實現,但具體的排序方法(升序還是降序)由子類決定:

// "Template Method defines an algorithm in terms of abstract operations that subclasses
// override to provide concrete behavior."  Here, doIt() is the algorithm, and needSwap() is the abstract operation.

#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;

class
 Sort {  ////// Shell sort //////
public:
    void
 doIt( int v[], int n )
    {

        for
 (int g = n/2; g > 0; g /= 2)
            for
 (int i = g; i < n; i++)
                for
 (int j = i-g; j >= 0; j -= g)
                    if
 (needSwap(v[j], v[j+g]))
                        doSwap(v[j], v[j+g]);
    }

private
:
    virtual
 int needSwap(int,int) = 0;
    void
 doSwap(int& a,int& b)
    {

        int
 t = a; a = b; b = t;
    }
};


class
 SortUp : public Sort
{

    int
 needSwap(int a, int b)
    {

        return
 (a > b);
    }
};

class
 SortDown : public Sort
{

    int
 needSwap(int a, int b)
    {

        return
 (a < b);
    }
};


void
 main( void )
{

    const
 int NUM = 10;
    int
        array[NUM];
    time_t    t;
    srand((unsigned) time(&t));
    for
 (int i=0; i < NUM; i++)
    {

        array[i] = rand() % 10 + 1;
        cout << array[i] << ' ';
    }

    cout << endl;

    SortUp  upObj;
    upObj.doIt( array, NUM );
    for
 (int u=0; u < NUM; u++)
        cout << array[u] << ' ';
    cout << endl;

    SortDown  downObj;
    downObj.doIt( array, NUM );
    for
 (int d=0; d < NUM; d++)
        cout << array[d] << ' ';
    cout << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章