天天看點

C#設計模式-模闆方法模式(Template Method)

概念

模闆指一些可以套用的公共内容,例如網頁模闆是當網站中有許多頁面版式色彩相同的情況下,将其定義為網頁模闆,并定義其中部分可編輯,部分不可編輯,那麼在利用網頁模闆制作其他頁面時就會很友善,不易出錯。

在設計模式中,模闆方法模式中模闆和生活中模闆概念非常類似,在一個抽象類中定義一個操作中的算法骨架(對應于模闆),而将一些步驟延遲到子類中去實作(對應根據自己的情況向模闆填充内容)。

在面向對象程式設計過程中,程式員常常會遇到這種情況:設計一個系統時知道了算法所需的關鍵步驟,而且确定了這些步驟的執行順序,但某些步驟的具體實作還未知,或者說某些步驟的實作與具體的環境相關。此時就可以采用模闆方法進行設計。

例如公司的入職流程,進入公司,入職準備、入職報到、辦理入職手續、進行入職教育訓練,轉正,入職結束進入崗位。這些步驟都很固定,但是不同的公司,流程中每個步驟稍有不同。這些不同的可以在具體實作上進行填充。

特點

優點:

它封裝了不變部分,擴充可變部分。它把認為是不變部分的算法封裝到父類中實作,而把可變部分算法由子類繼承實作,便于子類繼續擴充。

它在父類中提取了公共的部分代碼,實作了代碼複用。

部分方法是由子類實作的,是以子類可以通過擴充方式增加相應的功能,符合開閉原則。

缺點:

對每個不同的實作都需要定義一個子類,這會導緻類的個數增加,系統更加龐大,設計也更加抽象。

父類中的抽象方法由子類實作,子類執行的結果會影響父類的結果,這導緻一種反向的控制結構,它提高了代碼閱讀的難度。

因為引入了一個抽象類,如果具體實作過多的話,需要使用者或開發人員需要花更多的時間去理清類之間的關系。

模式結構

根據模闆方法模式類圖結構,有利于我們理清該模式中類之間的關系,具體類圖如下:

C#設計模式-模闆方法模式(Template Method)

模闆方法模式中涉及的角色:

抽象模闆角色:定義了一個或多個抽象操作,以便讓子類實作,這些抽象操作稱為基本操作。它由一個模闆方法和若幹個基本方法構成。

  模闆方法:定義了算法的骨架,按某種順序調用其包含的基本方法。

  基本方法:是整個算法中的一個步驟,包含了抽象方法、具體方法。

具體模闆角色:實作父類所定義的一個或多個抽象方法。

應用場景

算法的整體步驟很固定,但其中個别部分易變時,這時候可以使用模闆方法模式,将容易變的部分抽象出來,供子類實作。

當多個子類存在公共的行為時,可以将其提取出來并集中到一個公共父類中以避免代碼重複。首先,要識别現有代碼中的不同之處,并且将不同之處分離為新的操作。最後,用一個調用這些新的操作的模闆方法來替換這些不同的代碼。

實作

以入職流程為例,進行具體的實作。

using System;

namespace 模闆模式
{
    class EntryProcess
    {
        static void Main(string[] args)
        {
            SamsungEntryProcess samsung = new SamsungEntryProcess();
            HuaweiEntryProcess huawei = new HuaweiEntryProcess();

            samsung.JoiningCompany();
            huawei.JoiningCompany();

            Console.Read();
        }
    }

    // 抽象類,入職流程
    public abstract class TemplateEntryProcess
    {
        // 模闆方法,不要把模版方法定義為 Virtual 或 abstract 方法,避免被子類重寫,防止更改流程的執行順序
        public void JoiningCompany()
        {
            this.entryCompany(); // 進入公司
            this.preparationForEntry(); // 入職前準備,整理衣帽等
            this.registrationForEmployment(); // 入職報到
            this.entryProcedures(); // 辦理入職手續
            this.inductionTraining(); // 入職教育訓練
            this.evaluationOfConversion(); // 轉正評估
            this.entryOver(); // 入職結束,進入崗位
        }

        public abstract void entryCompany();

        public void preparationForEntry()
        {
            Console.WriteLine("做準備,整理衣帽等;");
        }

        public void registrationForEmployment()
        {
            Console.WriteLine("入職報到;");
        }
        public void entryProcedures()
        {
            Console.WriteLine("辦理入職手續;");
        }
        public void inductionTraining()
        {
            Console.WriteLine("進行入職教育訓練;");
        }
        public void evaluationOfConversion()
        {
            Console.WriteLine("完成入職前教育訓練,進行轉正評估;");
        }
        public void entryOver()
        {
            Console.WriteLine("入職流程完成,進入崗位。");
        }

    }

    // 具體子類,三星入職
    public class SamsungEntryProcess: TemplateEntryProcess
    {
        public override void entryCompany()
        {
            Console.WriteLine("進入三星公司");
        }

    }

    // 具體子類,華為入職
    public class HuaweiEntryProcess: TemplateEntryProcess
    {
        public override void entryCompany()
        {
            Console.WriteLine("進入華為公司");
        }
    }
}      

執行後結果

進入三星公司
做準備,整理衣帽等;
入職報到;
辦理入職手續;
進行入職教育訓練;
完成入職前教育訓練,進行轉正評估;
入職流程完成,進入崗位。
進入華為公司
做準備,整理衣帽等;
入職報到;
辦理入職手續;
進行入職教育訓練;
完成入職前教育訓練,進行轉正評估;
入職流程完成,進入崗位。      

繼續閱讀