模板方法模式深度解析(一):模板方法模式概述,模板方法模式結構與實現

原文鏈接:http://cmsblogs.com/?p=5098

. 模板方法模式概述

在現實生活中,很多事情都包含幾個實現步驟,例如請客吃飯,無論吃什麼,一般都包含點單、吃東西、買單等幾個步驟,通常情況下這幾個步驟的次序是:點單 –> 吃東西 –> 買單。在這三個步驟中,點單和買單大同小異,最大的區別在於第二步——吃什麼?吃麪條和吃滿漢全席可大不相同,如圖1所示:

20190615100116_1.png

圖1 請客吃飯示意圖

在軟件開發中,有時也會遇到類似的情況,某個方法的實現需要多個步驟(類似“請客”),其中有些步驟是固定的(類似“點單”和“買單”),而有些步驟並不固定,存在可變性(類似“吃東西”)。爲了提高代碼的複用性和系統的靈活性,可以使用一種稱之爲模板方法模式的設計模式來對這類情況進行設計,在模板方法模式中,將實現功能的每一個步驟所對應的方法稱爲基本方法(例如“點單”、“吃東西”和“買單”),而調用這些基本方法同時定義基本方法的執行次序的方法稱爲模板方法(例如“請客”)。在模板方法模式中,可以將相同的代碼放在父類中,例如將模板方法“請客”以及基本方法“點單”和“買單”的實現放在父類中,而對於基本方法“吃東西”,在父類中只做一個聲明,將其具體實現放在不同的子類中,在一個子類中提供“吃麪條”的實現,而另一個子類提供“吃滿漢全席”的實現。通過使用模板方法模式,一方面提高了代碼的複用性,另一方面還可以利用面向對象的多態性,在運行時選擇一種具體子類,實現完整的“請客”方法,提高系統的靈活性和可擴展性。

模板方法模式定義如下:

模板方法模式:定義一個操作中算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

模板方法模式是一種基於繼承的代碼複用技術,它是一種類行爲型模式

模板方法模式是結構最簡單的行爲型設計模式,在其結構中只存在父類與子類之間的繼承關係。通過使用模板方法模式,可以將一些複雜流程的實現步驟封裝在一系列基本方法中,在抽象父類中提供一個稱之爲模板方法的方法來定義這些基本方法的執行次序,而通過其子類來覆蓋某些步驟,從而使得相同的算法框架可以有不同的執行結果。模板方法模式提供了一個模板方法來定義算法框架,而某些具體步驟的實現可以在其子類中完成。

2. 模板方法模式結構與實現

2.1 模式結構

模板方法模式結構比較簡單,其核心是抽象類和其中的模板方法的設計,其結構如圖2所示:

20190615100118_2.png

圖2 模板方法模式結構圖

由圖2可知,模板方法模式包含如下兩個角色:

(1) AbstractClass(抽象類): 在抽象類中定義了一系列基本操作(PrimitiveOperations),這些基本操作可以是具體的,也可以是抽象的,每一個基本操作對應算法的一個步驟,在其子類中可以重定義或實現這些步驟。同時,在抽象類中實現了一個模板方法(Template Method),用於定義一個算法的框架,模板方法不僅可以調用在抽象類中實現的基本方法,也可以調用在抽象類的子類中實現的基本方法,還可以調用其他對象中的方法。

(2) ConcreteClass(具體子類): 它是抽象類的子類,用於實現在父類中聲明的抽象基本操作以完成子類特定算法的步驟,也可以覆蓋在父類中已經實現的具體基本操作。

2.2 模式實現

在實現模板方法模式時,開發抽象類的軟件設計師和開發具體子類的軟件設計師之間可以進行協作。一個設計師負責給出一個算法的輪廓和框架,另一些設計師則負責給出這個算法的各個邏輯步驟。實現這些具體邏輯步驟的方法即爲基本方法,而將這些基本方法彙總起來的方法即爲模板方法,模板方法模式的名字也因此而來。下面將詳細介紹模板方法和基本方法:

1. 模板方法

一個模板方法是定義在抽象類中的、把基本操作方法組合在一起形成一個總算法或一個總行爲的方法。這個模板方法定義在抽象類中,並由子類不加以修改地完全繼承下來。模板方法是一個具體方法,它給出了一個頂層邏輯框架,而邏輯的組成步驟在抽象類中可以是具體方法,也可以是抽象方法。由於模板方法是具體方法,因此模板方法模式中的抽象層只能是抽象類,而不是接口。

2. 基本方法

基本方法是實現算法各個步驟的方法,是模板方法的組成部分。基本方法又可以分爲三種:抽象方法(Abstract Method)、具體方法(Concrete Method)和鉤子方法(Hook Method)。

(1) 抽象方法:一個抽象方法由抽象類聲明、由其具體子類實現。在C#語言裏一個抽象方法以abstract關鍵字標識。

(2) 具體方法:一個具體方法由一個抽象類或具體類聲明並實現,其子類可以進行覆蓋也可以直接繼承。

(3) 鉤子方法:一個鉤子方法由一個抽象類或具體類聲明並實現,而其子類可能會加以擴展。通常在父類中給出的實現是一個空實現(可使用virtual關鍵字將其定義爲虛函數),並以該空實現作爲方法的默認實現,當然鉤子方法也可以提供一個非空的默認實現。

在模板方法模式中,鉤子方法有兩類:第一類鉤子方法可以與一些具體步驟“掛鉤”,以實現在不同條件下執行模板方法中的不同步驟,這類鉤子方法的返回類型通常是bool類型的,這類方法名一般爲IsXXX(),用於對某個條件進行判斷,如果條件滿足則執行某一步驟,否則將不執行,如下代碼片段所示:

    ……
    //模板方法
    public void TemplateMethod()
    {
    Open();
    Display();
    //通過鉤子方法來確定某步驟是否執行
    if (IsPrint())
    {
        Print();
    }
    }

    //鉤子方法
    public bool IsPrint()
    {
        return true;
    }
    ……

在代碼中IsPrint()方法即是鉤子方法,它可以決定Print()方法是否執行,一般情況下,鉤子方法的返回值爲true,如果不希望某方法執行,可以在其子類中覆蓋鉤子方法,將其返回值改爲false即可,這種類型的鉤子方法可以控制方法的執行,對一個算法進行約束。

還有一類鉤子方法就是實現體爲空的具體方法,子類可以根據需要覆蓋或者繼承這些鉤子方法,與抽象方法相比,這類鉤子方法的好處在於子類如果沒有覆蓋父類中定義的鉤子方法,編譯可以正常通過,但是如果沒有覆蓋父類中聲明的抽象方法,編譯將報錯。

在模板方法模式中,抽象類的典型代碼如下:

    abstract class AbstractClass
    {
    //模板方法
    public void TemplateMethod()
    {
            PrimitiveOperation1();
            PrimitiveOperation2();
            PrimitiveOperation3();
    }

    //基本方法—具體方法
    public void PrimitiveOperation1()
    {
        //實現代碼
    }

    //基本方法—抽象方法
        public abstract void PrimitiveOperation2();    

    //基本方法—鉤子方法
    public virtual void PrimitiveOperation3()   
    {  }
    }

在抽象類中,模板方法TemplateMethod()定義了算法的框架,在模板方法中調用基本方法以實現完整的算法,每一個基本方法如PrimitiveOperation1()、PrimitiveOperation2()等均實現了算法的一部分,對於所有子類都相同的基本方法可在父類提供具體實現,例如PrimitiveOperation1(),否則在父類聲明爲抽象方法或鉤子方法,由不同的子類提供不同的實現,例如PrimitiveOperation2()和PrimitiveOperation3()。

可在抽象類的子類中提供抽象步驟的實現,也可覆蓋父類中已經實現的具體方法,具體子類的典型代碼如下:

    class ConcreteClass : AbstractClass
    {
    public override void PrimitiveOperation2()
    {
        //實現代碼
    }

    public override void PrimitiveOperation3()
    {
        //實現代碼
    }
    }

在模板方法模式中,由於面向對象的多態性,子類對象在運行時將覆蓋父類對象,子類中定義的方法也將覆蓋父類中定義的方法,因此程序在運行時,具體子類的基本方法將覆蓋父類中定義的基本方法,子類的鉤子方法也將覆蓋父類的鉤子方法,從而可以通過在子類中實現的鉤子方法對父類方法的執行進行約束,實現子類對父類行爲的反向控制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章