模板方法模式深度解析(三)

Liuwei-Sunny發表於2012-12-15

4 鉤子方法的使用

     

       模板方法模式中,在父類中提供了一個定義演算法框架的模板方法,還提供了一系列抽象方法、具體方法和鉤子方法,其中鉤子方法的引入使得子類可以控制父類的行為。最簡單的鉤子方法就是空方法,程式碼如下:

public virtual void Display() {   }

      當然也可以在鉤子方法中定義一個預設的實現,如果子類不覆蓋鉤子方法,則執行父類的預設實現程式碼。

      另一種鉤子方法可以實現對其他方法進行約束,這種鉤子方法通常返回一個bool型別,即返回truefalse,用來判斷是否執行某一個基本方法,下面通過一個例項來說明這種鉤子方法的使用。

      某軟體公司欲為銷售管理系統提供一個資料圖表顯示功能,該功能的實現包括如下幾個步驟:

      (1) 從資料來源獲取資料;

      (2) 將資料轉換為XML格式;

      (3) 以某種圖表方式顯示XML格式的資料。

      該功能支援多種資料來源和多種圖表顯示方式,但所有的圖表顯示操作都基於XML格式的資料,因此可能需要對資料進行轉換,如果從資料來源獲取的資料已經是XML資料則無須轉換。

       由於該資料圖表顯示功能的三個步驟次序是固定的,且存在公共程式碼(例如資料格式轉換程式碼),滿足模板方法模式的適用條件,可以使用模板方法模式對其進行設計。因為資料格式的不同,XML資料可以直接顯示,而其他格式的資料需要進行轉換,因此第(2)步“將資料轉換為XML格式”的執行存在不確定性,為了解決這個問題,可以定義一個鉤子方法IsNotXMLData()來對資料轉換方法進行控制。通過分析,該圖表顯示功能的基本結構如圖4所示:

圖4  資料圖表顯示功能結構圖

       可以將公共方法和框架程式碼放在抽象父類中,程式碼如下:

//DataViewer.cs
using System;

namespace TemplateMethodSample
{
    abstract class DataViewer
    {
        //抽象方法:獲取資料
        public abstract void GetData();

        //具體方法:轉換資料
        public void ConvertData() 
        {
		    Console.WriteLine("將資料轉換為XML格式。");
	    }

        //抽象方法:顯示資料
        public abstract void DisplayData();

        //鉤子方法:判斷是否為XML格式的資料
        public virtual bool IsNotXMLData()
        {
            return true;
        }

        //模板方法
        public void Process()
        {
            GetData();
            //如果不是XML格式的資料則進行資料轉換
            if (IsNotXMLData())
            {
                ConvertData();
            }
            DisplayData();
        }
    }
}

       在上面的程式碼中,引入了一個鉤子方法IsNotXMLData(),其返回型別為bool型別,在模板方法中通過它來對資料轉換方法ConvertData()進行約束,該鉤子方法的預設返回值為true,在子類中可以根據實際情況覆蓋該方法,其中用於顯示XML格式資料的具體子類XMLDataViewer程式碼如下:

//XMLDataViewer.cs
using System;

namespace TemplateMethodSample
{
    class XMLDataViewer : DataViewer
    {
        //實現父類方法:獲取資料
        public override void GetData() 
        {
		    Console.WriteLine("從XML檔案中獲取資料。");
	    }

        //實現父類方法:顯示資料,預設以柱狀圖方式顯示,可結合橋接模式來改進
        public override void DisplayData() 
        {
            Console.WriteLine("以柱狀圖顯示資料。");
	    }

        //覆蓋父類的鉤子方法
        public override bool IsNotXMLData()
        {
            return false;
        }
    }
}

       在具體子類XMLDataViewer中覆蓋了鉤子方法IsNotXMLData(),返回false,表示該資料已為XML格式,無須執行資料轉換方法ConvertData(),客戶端程式碼如下:

//Program.cs
using System;

namespace TemplateMethodSample
{
    class Program
    {
        static void Main(string[] args)
        {
            DataViewer dv;
            dv = new XMLDataViewer();
            dv.Process();
            Console.Read();
        }
    }
}

       該程式執行結果如下:

XML檔案中獲取資料。

以柱狀圖顯示資料。

 

5 模板方法模式效果與適用場景

       模板方法模式是基於繼承的程式碼複用技術,它體現了物件導向的諸多重要思想,是一種使用較為頻繁的模式。模板方法模式廣泛應用於框架設計中,以確保通過父類來控制處理流程的邏輯順序(如框架的初始化,測試流程的設定等)。

 

       5.1 模式優點

       模板方法模式的主要優點如下:

       (1) 在父類中形式化地定義一個演算法,而由它的子類來實現細節的處理,在子類實現詳細的處理演算法時並不會改變演算法中步驟的執行次序。

       (2) 模板方法模式是一種程式碼複用技術,它在類庫設計中尤為重要,它提取了類庫中的公共行為,將公共行為放在父類中,而通過其子類來實現不同的行為,它鼓勵我們恰當使用繼承來實現程式碼複用。

       (3) 可實現一種反向控制結構,通過子類覆蓋父類的鉤子方法來決定某一特定步驟是否需要執行。

       (4) 在模板方法模式中可以通過子類來覆蓋父類的基本方法,不同的子類可以提供基本方法的不同實現,更換和增加新的子類很方便,符合單一職責原則和開閉原則。

 

       5.2 模式缺點

       模板方法模式的主要缺點如下:

       需要為每一個基本方法的不同實現提供一個子類,如果父類中可變的基本方法太多,將會導致類的個數增加,系統更加龐大,設計也更加抽象,此時,可結合橋接模式來進行設計。

 

       5.3 模式適用場景

       在以下情況下可以考慮使用模板方法模式:

       (1) 對一些複雜的演算法進行分割,將其演算法中固定不變的部分設計為模板方法和父類具體方法,而一些可以改變的細節由其子類來實現。即:一次性實現一個演算法的不變部分,並將可變的行為留給子類來實現。

       (2) 各子類中公共的行為應被提取出來並集中到一個公共父類中以避免程式碼重複。

       (3) 需要通過子類來決定父類演算法中某個步驟是否執行,實現子類對父類的反向控制。


 【作者:劉偉   http://blog.csdn.net/lovelion 

相關文章