前言:
本來早就想寫寫和代碼設計相關的東西了,以前做2DX的時候就有過寫寫觀察者設計模式的想法,但是實踐不多。現在轉到U3D的懷抱中,倒是接觸了不少委托事件的寫法,那干脆就在此總結一下吧。
1.C#中的委托、事件引入
本想去找一些高端的介紹來開場,但是找來找去感覺還是用百度百科中的例子來開場也是蠻適合的。當然要具體到Unity3d,我們還是要按照U3d的格式來寫。
首先我們來看百度百科這個例子寫的是什么?
ok,原來是全球化形勢下,不同語種的小伙伴們問候早安時候的一個情景。那么最直觀的做法,無非是判斷哪國人,然后說英語的調用說英語的方法,說中文的調用說中文的方法,之后再有說日語的,說法語的還要再調用說日語的,說法語的方法。這樣做當然OK,但是拓展性很差。
首先是不考慮使用委托時的寫法
using UnityEngine; using System.Collections; public class delegateFanyoy : MonoBehaviour { // Use this for initialization public UIButton testBtn; void Start () { EventDelegate.Add (this.testBtn.onClick, this.BtnClick); } public void BtnClick() { GoodMoring ("chenjd"); } public void GoodMoring(string name) { Debug.Log ("GoodMoring " + name); } // Update is called once per frame void Update () { } }
很簡單,首先利用EventDelegate為按鈕的OnClick事件綁定一個方法,用來測試我們上面提到的問早安的功能。
結果如下:
那么問題來了,小匹夫可是堂堂中國人啊,怎么能不說中文反而天天鼓搗英語呢?所以剛剛實現問早的方法GoodMoring()就不能用咯,還要新寫一個方法,要輸出中文早安,然后再和點擊按鈕的事件綁定。這樣是不是很麻煩呢?
如果有小伙伴覺得不麻煩,那小匹夫只能演示一種小匹夫認為不使用委托的前提下最直接的一種寫法了。這時候,GoodMoring就需要改一改了,肯定要根據不同的人來選擇不同的問候語咯。這里為了方便,定義一個枚舉Language作為判斷的依據:
using UnityEngine; using System.Collections; public class delegateFanyoy : MonoBehaviour { // Use this for initialization public UIButton testBtn; void Start () { EventDelegate.Add (this.testBtn.onClick, this.BtnClick); } public void BtnClick() { GoodMoring ("chenjd", Language.Chinese); } public void GoodMoring(string name, Language l) { switch (l) { case Language.Chinese: MoringChinese(name); break; case Language.English: MoringEnglish(name); break; } } public void MoringChinese(string n) { Debug.Log ("早上好 " + n); } public void MoringEnglish(string n) { Debug.Log ("goodmoring" + n); } public enum Language { Chinese, English } // Update is called once per frame void Update () { } }
如果再來一個日語普通話的小伙伴,或者再來一個韓語思密達的小伙伴,那么不可避免我們需要去修改GoodMoring這個函數去實現判斷並調用正確的語言輸出方法。這樣拓展性體現在哪里呢?
如果說能有一個方法A,它的參數也是一個方法B,那么我們保留那個方法A而只需要傳入不同的參數(方法B),不就可以靈活的應對了嗎?再來一個日本人,一個韓國人,無非只是將說日語和說韓語的方法B傳入到那個無需改動的方法A中就可以了,點擊按鈕觸發的事件只需要方法A響應就可以咯。這里方法A就是我們的GoodMoring方法,而方法B作為參數是不同語言的MoringXXXX方法。
那么我們就可以引入代理的概念了。嗯,是那句很老套的——方法的參數是方法。
2.方法的參數是方法
那么我們開始進行第一步分析,千里之行始於足下嘛。
既然方法A的某個參數是方法B,我們所要利用的無非就是使用傳入的方法B。所以我們之前的方法A--GoodMoring(string name, language l)方法就變成了
GoodMoring(string name, XXX MoringLanguage) { MoringLanguage(name); }
直接調用作為參數傳入的方法。
但是這里又有新的問題出現了,涉及到要將方法作為參數傳入另一個方法,我們都知道,參數的傳入是需要有類型的呀。你MoringLanguage到底是個啥?
這里我們似乎又想到了,區分方法,無非是它的返回值,和傳入參數類型個數。想到這里,豁然開朗,只要我們規定了傳入的MoringLanguage的返回類型和MoringLanguage的參數類型是不是就可以證明傳入的MoringLanguage的身份了呢?對!這就是代理了delegate了。
那我們按照MoringChinese和MoringEnglish的返回類型和參數類型來定義這個委托。
public delegate void MoringDelegate(string name);
那么我們將GoodMoring的修改為
GoodMoring(string name, MoringDelegate MoringLanguage) { MoringLanguage(name); }
就可以了。下面上代碼。
using UnityEngine; using System.Collections; public class delegateFanyoy : MonoBehaviour { // Use this for initialization public UIButton testBtn; void Start () { EventDelegate.Add (this.testBtn.onClick, this.BtnClick); } public void BtnClick() { GoodMoring ("chenjd", MoringEnglish); GoodMoring ("小匹夫", MoringChinese); } public void GoodMoring(string name, MoringDelegate MoringLanguage) { MoringLanguage (name); }
public delegate void MoringDelegate(string n); public void MoringChinese(string n) { Debug.Log ("早上好 " + n); } public void MoringEnglish(string n) { Debug.Log ("goodmoring" + n); } public enum Language { Chinese, English } // Update is called once per frame void Update () { } }
最后,做個小結,也用一句在網上爛大街的話好了。所謂委托就是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞,這種將方法動態地賦給參數的做法,可以避免在程序中大量使用If … Else(Switch)語句,同時使得程序具有更好的可擴展性喲。