1. 程式人生 > >C# 設計模式(六)模板方法模式(unity演示)

C# 設計模式(六)模板方法模式(unity演示)

1、引言

   說到模板,我們很容易想到生活中的例子,像“簡歷模板”、“論文模板”、“競選模板”等。而這些模板有一個共同的特徵就是,它們有一個約定俗成的格式,我們能可以拿著這些模板按照我們自己的實際情況來填寫裡面的內容。像“簡歷模板”就是個十分常見的例子,我們在簡歷模板上只需要根據內容填寫自己的實際情況就完成了自己的簡歷。在設計模式中,模板方法模式中所說的模板與生活中的模板也十分相似,下面讓我們一起來了解下。

2、模板方法模式詳細介紹

2.1、模板方法模式的定義

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

  • 理解
    在一個抽象類中定義一個操作中的演算法骨架(對應於生活中的大家下載的模板),而將一些步驟延遲到子類中去實現(對應於我們根據自己的情況向模板填充內容)。模板方法使得子類可以不改變一個演算法的結構前提下,重新定義演算法的某些特定步驟,模板方法模式把不變行為搬到超類中,從而去除了子類中的重複程式碼。

2.2、模板方法模式的結構

  下面是模板方法模式的類圖,我們一起來看看!
這裡寫圖片描述

通過上圖我們不難發現,在模板方法模式中只有兩個角色:

  • 抽象模板角色:定義了一個或多個抽象操作,以便讓子類實現,這些抽象操作稱為基本操作。
  • 具體模板角色:實現父類所定義的一個或多個抽象方法。每個AbsrtactClass可以由任意多個ConcreteClass與之對應,而每個ConcreteClass都可以給出這些抽象方法(也就是頂級邏輯的實現步驟)的不同實現,從而使得頂級邏輯的實現各不相同。

2.3、模板方法模式的類圖實現

詳細程式碼如下:
模板抽象類:

/// <summary>
/// 抽象類
/// </summary>
public abstract class AbstractClass
{

   /// <summary>
   /// 要放到子類中實現的一些抽象行為
   /// </summary>
   public abstract void PrimitiveOperation1();
   public abstract void PrimitiveOperation2();

    /// <summary>
    ///
模板方法,給出了邏輯的骨架,
/// 而邏輯的組成是一些相應的抽象操作,他們都推遲到子類中實現 /// </summary> public void TemplateMethod() { PrimitiveOperation1(); PrimitiveOperation2(); Console.WriteLine("父類模板"); } }

具體類:

/// <summary>
/// 具體類A
/// </summary>
public class ConcreteClassA : AbstractClass
{

    /// <summary>
    /// 具體行為
    /// </summary>
    public override void PrimitiveOperation1()
    {
        Console.WriteLine("子類A,方法1實現");
    }

    /// <summary>
    /// 具體行為
    /// </summary>
    public override void PrimitiveOperation2()
    {
        Console.WriteLine("子類A,方法2實現");
    }
}


public class ConcreteClassB : AbstractClass
{
    public override void PrimitiveOperation1()
    {
        Console.WriteLine("子類b,方法1實現");
    }

    public override void PrimitiveOperation2()
    {
        Console.WriteLine("子類B,方法2實現");
    }
}

測試一下:

//將子類的變數的宣告改成了父類,利用多型實現程式碼的複用
AbstractClass c;

c = new ConcreteClassA();
c.TemplateMethod();

c = new ConcreteClassB();
c.TemplateMethod();

測試結果:

子類A,方法1實現
子類A,方法2實現
父類模板
子類b,方法1實現
子類B,方法2實現
父類模板

2.4、C#舉例

  • 情景設定:
      炒蔬菜的做法:倒油——油熱——倒入蔬菜——翻炒

蔬菜抽象類:

/// <summary>
/// 蔬菜抽象類
/// <summary>
public abstract class Vegetabel
{
    // 模板方法,不要把模版方法定義為Virtual或abstract方法,
    //避免被子類重寫,防止更改流程的執行順序
    public void CookVegetabel()
    {
        Console.WriteLine("抄蔬菜的一般做法");
        this.pourOil();
        this.HeatOil();
        this.pourVegetable();
        this.stir_fry();
    }

    // 第一步倒油
    public void pourOil()
    {
        Console.WriteLine("倒油");
    }

    // 把油燒熱
    public void HeatOil()
    {
        Console.WriteLine("把油燒熱");
    }

    // 油熱了之後倒蔬菜下去,具體哪種蔬菜由子類決定
    public abstract void pourVegetable();

    // 開發翻炒蔬菜
    public void stir_fry()
    {
        Console.WriteLine("翻炒");
    }
}

具體類:

// 菠菜
public class Spinach : Vegetabel
{

    public override void pourVegetable()
    {
        Console.WriteLine("倒菠菜進鍋中");
    }
}

// 大白菜
public class ChineseCabbage : Vegetabel
{
    public override void pourVegetable()
    {
        Console.WriteLine("倒大白菜進鍋中");
    }
}

測試一下:

// 建立一個菠菜例項並呼叫模板方法
Spinach spinach = new Spinach();
spinach.CookVegetabel();

測試結果:

抄蔬菜的一般做法
倒油
把油燒熱
倒菠菜進鍋中
翻炒

3、模板方法模式的優缺點

下面我們來看看模板方法模式的優缺點:

  • 優點

    1. 實現了程式碼複用
    2. 能夠靈活應對子步驟的變化,符合開放-封閉原則
  • 缺點

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

4、應用情景

下面我們來看看模板方法模式的使用情景:

  • 一次性實現一個演算法的不變的部分,並將可變的行為留給子類來實現;
  • 各子類中公共的行為應被提取出來並集中到一個公共父類中以避免程式碼重複;
  • 控制子類的擴充套件。

5、 應用舉例(unity)

模板類:

using UnityEngine;
using UnityEngine.UI;
using System;

public class Template  {

    protected Text mBtnText;
    protected Text mText;
    protected Image mImage;
    protected Action Callback;
    protected Button button;

    public Template() { }

    protected void Init(Transform transform)
    {
        mBtnText = transform.Find("Button/Text").GetComponent<Text>();
        mText = transform.Find("Text").GetComponent<Text>();
        mImage = transform.Find("Image").GetComponent<Image>();

        button = transform.Find("Button").GetComponent<Button>();
        button.onClick.RemoveAllListeners();
        button.onClick.AddListener(OnClick);
    }

    public void OnClick()
    {
        Debug.Log("點選了按鈕:" + mBtnText.text);
        if (Callback != null)
            Callback();
    }

    protected virtual void Method1()
    {
    }

    public void TemplateMethod(Transform transform)
    {
        Init(transform);
        Method1();
    }
}

具體類A:

using UnityEngine;

public class ConcreteTemplateA : Template {
    protected override void Method1()
    {
        base.Method1();
        mText.text = "模板方法A";
        mBtnText.text = "模板方法A按鈕";
        mImage.color = Color.green;
        Callback = OnClickA;
    }

    private void OnClickA()
    {
        Debug.Log("模板方法A的按鈕事件");
    }

}

具體類B:

using UnityEngine;

public class ConcreteTemplateB : Template
{
    protected override void Method1()
    {
        mText.text = "模板方法B";
        mBtnText.text = "模板方法B按鈕";
        mImage.color = Color.yellow;
        Callback = null;
        Callback = OnClickB;
    }

    private void OnClickB()
    {
        Debug.Log("模板方法B的按鈕事件");
    }
}

測試一下:

using UnityEngine;

public class Test : MonoBehaviour {

    void OnGUI()
    {
        if (GUI.Button(new Rect(100, 100, 120, 50), "按鈕A"))
        {
            Template a = new ConcreteTemplateA();
            a.TemplateMethod(this.transform);
        }

        if (GUI.Button(new Rect(100, 200, 120, 50), "按鈕B"))
        {
            Template b = new ConcreteTemplateB();
            b.TemplateMethod(this.transform);
        }
    }
}

測試指令碼掛在Canvas上

這裡寫圖片描述

運先點選按鈕A或B,再點選右邊白色按鈕。行結果如下:
這裡寫圖片描述
這裡寫圖片描述

6、總結

  到這裡,模板方法模式的介紹就結束了,模板方法模式在抽象類中定義了演算法的實現步驟,將這些步驟的實現延遲到具體子類中去實現,從而使所有子類複用了父類的程式碼,所以模板方法模式是基於繼承的一種實現程式碼複用的技術。

7、unity工程下載

  在文章的最後我們給出上述例子的工程下載連結,方便朋友們探討交流!本次演示版本Unity5.6.3f1(64-bit),VS2015需要下載的朋友,請點擊此處下載

The End
  好了,今天的分享就到這裡,如有不足之處,還望大家及時指正,隨時歡迎探討交流!!!

喜歡的朋友們,請幫頂、點贊、評論!您的肯定是我寫作的不竭動力!