設計模式——模版方法模式

shanzm-2020年7月20日 01:55:50

1. 簡介

1.定義git

模版方法模式(Template Method Pattern):用於定義一個操做中算法的骨架,而將一些步驟延遲到子類中。github

模版方法模式使得子類能夠不改變一個算法的結構及可重定義該算法的某些特定步驟。算法

簡而言之:模版方法模式功能在於固定算法骨架,而讓具體算法實現可擴展。sql

其實只要是理解繼承和多態便可以當即明白模版方法模式。模版方法模式是經過把不變行爲搬移到父類,除去子類中的重複代碼。數據庫

2.主要類設計模式

  • AbstractClass:抽象類。用來定義算法骨架(抽象方法)。具體的子類經過重寫抽象方法來實現一個算法的各個步驟。oracle

  • ConcreteClass:具體實現類。用來實現算法骨架中的某些步驟,完成與特定子類相關的功能。ide

3.名詞解釋函數

  • 模版方法:抽象類中定義算法骨架的方法。設計

  • 原語操做:即抽象方法,抽象類中定義的抽象操做。

  • 具體操做:即具體方法,抽象類定義的具體方法體的方法

  • 鉤子方法:用於決定模版方法中某個方法是否執行的方法。鉤子方法就是經過子類的行爲去反向控制父類的行爲的一種方法

4.抽象工廠模式的UML

Template Method Pattern UML

注:原圖片來自《設計模式實訓教程-第二版》


2. 示例

2.1 背景說明

對數據庫的操做:鏈接-->打開-->使用-->關閉

對於不一樣的數據操做步驟都是同樣的,只是鏈接數據庫稍有不一樣

這裏咱們定義一個抽象模版類DBOperator,其中咱們定義ConnDB()、OpenDB()、UseDB()、CloseDB()四個抽象方法

定義不一樣的數據庫具體實現類:SQLServerDBOperator、OracleDBOperator

2.2 代碼實現

①定義抽象父類

public abstract class DBOperator
{
    //原語操做1
    public abstract void ConnDB();
    //原語操做2
    public void OpenDB()
    {
        Console.WriteLine("打開數據庫");
    }
    //原語操做3
    public void UseDB()
    {
        Console.WriteLine("使用數據庫");
    }
    //原語操做4
    public void CloseDB()
    {
        Console.WriteLine("關閉數據庫");
    }

    //鉤子方法:用於子類反向控制父類中某個方法是否執行
    //注意鉤子方法這裏定義爲虛方法,虛方法和抽象方法不一樣的地方就是虛方法有方法體,這樣咱們就能夠在虛方法中定義默的方法
    public virtual bool IsStart()
    {
        return true;//默認爲true因此在具體子類中重寫
    }

    //模版方法:定義算法骨架
    //肯定其餘基本方法的執行順序
    public void Process()
    {
        ConnDB();
        OpenDB();
        if (IsStart())//經過鉤子方法控制是否執行UseDB()
        {
            UseDB();
        }
        CloseDB();
    }
}

②定義具體實現類

//具體子類1
public class OracleDBOperator : DBOperator
{
    public override void ConnDB()
    {
        Console.WriteLine("鏈接Oracle數據庫");
    }
    //按照面向對象的思想,咱們能夠在子類中使用new 關鍵字覆蓋父類中的方法
    //注意:
    //1. 這裏覆蓋了UseDB(),是不夠的,還要覆蓋調用這個方法的方法Process()
    //2. 如果父類引用指向子類對象,則須要將父類轉化爲子類對象纔可使用子類中覆蓋的方法
    public new void UseDB()
    {
        Console.WriteLine("使用Oracle數據庫");
    }

    public new void Process()
    {
        ConnDB();
        OpenDB();
        if (IsStart())
        {
            UseDB();
        }
        CloseDB();
    }
}

//具體子類2
public class SQLServerDBOperator : DBOperator
{
    ///具體子類繼承抽象父類,重寫抽象父類中的抽象方法
    ///抽象父類中的非抽象方法就是每一個子類都通用的方法,
    public override void ConnDB()
    {
        Console.WriteLine("鏈接SQL Server數據庫");
    }

    public override bool IsStart()//覆蓋了鉤子函數,修改了抽象父類中模版方法,實現子類反向控制父類
    {
        return false;
    }
}

③客戶端

static void Main(string[] args)
{
     static void Main(string[] args)
        {
            DBOperator sqlServerDBOperator = new SQLServerDBOperator();
            DBOperator oracleDBOperator = new OracleDBOperator();

            sqlServerDBOperator.Process(); //注意這裏,咱們定義的鉤子方法是虛方法,經過重寫,實現子類控制父類,這裏是不須要將強轉爲子類對象
            Console.WriteLine("---------------------------");

            oracleDBOperator.Process();
            Console.WriteLine("---------------------------");

            ((OracleDBOperator)oracleDBOperator).Process(); //這裏是經過覆蓋父類中的方法,因此須要將父類強轉爲相應的子類對象
            Console.WriteLine("---------------------------");

            Console.ReadKey();
        }
}

④運行結果

鏈接SQL Server數據庫
打開數據庫
關閉數據庫
---------------------------
鏈接Oracle數據庫
打開數據庫
使用數據庫
關閉數據庫
---------------------------
鏈接Oracle數據庫
打開數據庫
使用Oracle數據庫
關閉數據庫


3. 總結分析

3.1 補充

1.模版方法模式中爲什麼使用的是抽象類而不是接口?

這裏先說明一下接口和抽象類的區別:

  • 接口只是定義一組行爲,某個類(非抽象類)實現這個接口就須要使用該接口中的全部方法。簡而言之:接口約束實現該接口的類的行爲。因此接口也稱之爲契約。

  • 抽象類中的抽象方法須要子類重寫,而抽象類能夠有非抽象方法,非抽象方法是須要在抽象類中寫方法體的。簡而言之:抽象類不只約束子類的行爲並且須要爲子類中非抽象方法提供方法體

這裏咱們使用抽象類而不是使用接口,爲何呢?如果定義爲抽象方法則咱們須要在實現類中須要對抽象方法都重寫,而可能多個子類中的某個方法實現是同樣的。

這裏也體現了接口和抽象類的不一樣之處:接口約束實現接口的類行爲(因此接口也稱之爲契約)而抽象類不只要約束子類的行爲,而要爲子類提供公共方法體

這裏示例中的數據庫鏈接函數ConnDB定義爲抽象方法,由於每一個數據庫的鏈接方法是不同的,因此在每一個具體的實現類中都須要對其重寫 。而其餘的數據庫操做方法相似,因此咱們在父類中對其實現,避免子類中代碼冗餘。

3.2 優勢

模板方法模式的優勢是實現代碼複用。
模板方法模式是一種實現代碼複用的很好的手段。經過把子類的公共功能提煉和抽取,把公共部分放到模板中去實現。

模版方法模式體現類開閉原則。首先模版方法模式從設計上分離變與不變,而後把不變的部分抽取出來,定義到父類中,好比算法骨架,一些公共的、固定的實現等。這些不變的部分被封閉起來,儘可能不去修改它們。要想擴展新的功能,那就使用子類來擴展,經過子類來實現可變化的步驟,對於這種新增功能的作法是開放的。

3.3 缺點

模板方法模式的缺點是算法骨架不容易升級。
模板方法模式最基本的功能就是經過模板的制定,把算法骨架徹底固定下來。事實上模板和子類是很是耦合的,若是要對模板中的算法骨架進行變動,可能就會要求全部相關的子類進行相應的變化。好比模版方法中添加一個抽象方法,則全部的子類都須要去實現這方法。
因此抽取算法骨架的時候要特別當心,儘可能確保是不會變化的部分才放到模板中。

3.4 適應場合

建議在如下狀況中選用模板方法模式

  • 須要固定定義算法骨架。實現一個算法的不變的部分,並把可變的行爲留給子類來實現的狀況。
  • 各個子類中具備公共行爲,應該抽取出來,集中在一個公共類中去實現,從而避免代碼重複。
  • 須要控制子類擴展的狀況。模板方法模式會在特定的點來調用子類的方法,這樣只容許在這些點進行擴展。

3.5 對比與合用

【TODO】(待策略模式研究完在完成此部分!)

  • 模版方法模式與工廠方法模式

  • 模版方法模式和策略模式



4. 參考及源碼

相關文章
相關標籤/搜索