泛型PureMVC--Unity3d

由於前期項目需要,在Unity3d開發程序中引入了PrueMVC架構,該架構對Unity3d界面和邏輯之前的解耦合起到了極大的作用。由於網上PureMVC相關的資源實在是多的不得了,而且本人是較晚的使用者,偶然用在了Unity3d,下面主要說一些和unity結合的部分以及對這個駕構的優化。

爲什麼說要優化呢,其存在這麼多年了,優化得還不夠麼?主要是考慮到和具體的語言和應用場合不同,做適當的修改以利於開發。二是語言本身也在向前進步,如c#現在又出了不少的新特性。說優化,其實我也還不夠格的,畢竟作者創造了這個駕校,而我現在也就會用而已...

對於Unity而言,線程中絕對訪問不了引擎的組件已經是不用懷疑了,所以如果想要讓pureMVC的commond類執行在線程中,有必要考慮增加協程的使用;至於Mediator類,自然是需要做爲組件掛到遊戲物體上去的;最爲重要的一點,原pureMVC大量使用了拆箱和裝箱過程,這樣總感覺不是很方便,於是有了將其和泛型結合起來的想法;至於Proxy類,默認的名字應該改爲繼承於Proxy類的那個腳本名更合理一些;

下面來看一些具體的吧:

public interface INotification
{
    string ObserverName { get; set; }
    Type Type { get; set; }
    string ToString { get; }
}

public interface INotification<T>:INotification{
    T Body { get; set; }
}
這便是最後的信息交流的類Notifacation的接口,將其寫爲泛型就可以保存想傳什麼類型的數據都可以,而且不用裝拆箱。一定會有人問爲什麼要寫一個INotification爲個接口,爲什麼不用一個泛型的就可以了,主要使用過程中commond的需要數據類型不好確定,大多數情況下其實只執行其中的一個方法,而且可以重複執行,感覺沒有必要保存一個Type,然後用反射來生成新的Command

public interface ICommand<T>:ICommand
{
    void Execute(INotification<T> notify);
}
public interface ICommand{}
這樣一來,如果一個Command類的不需要參數,和需要參數分別可以從下面兩個類中繼承:

public abstract class SimpleCommand : Notifyer, ICommand
{
    public abstract void Execute(INotification<object> notification);
}
public abstract class ValueCommand<T> : Notifyer, ICommand<T>
{
    public abstract void Execute(INotification<T> notification);
}

}

但要注意的一件事,在發送信息時,參數類型必須一至,因爲在這個架構的Observer中依然使用了反射,如果向註冊的對象傳不同類型的參數,會報錯的!

Facade、Proxy,Commond直接繼承了Notifyer,可以直接調用其中的發送信息的方法

public void SendNotification(string observeName)
    {
        NotifyObservers(new Notification<object>(observeName));
    }
    public void SendNotification<T>(string observeName)
    {
        NotifyObservers(new Notification<T>(observeName));
    }
    public void SendNotification<T>(string observeName, T body)
    {
        NotifyObservers(new Notification<T>(observeName, body));
    }
    public void SendNotification<T>(string observeName, T body, Type type)
    {
        NotifyObservers(new Notification<T>(observeName, body, type));
    }

因爲C#不支持多繼承,所以Mediator類想要改善這些信息,只能繼承處接口重新寫一次這些方法了,但實際上Proxy可以在數據註冊後發送信息,而Mediator類主要是接收信息的對象,因此在Mediator類重新寫一遍沒有什麼必要性;

public abstract  class Mediator<T> : MonoBehaviour, IMediator<T>
{
    public virtual void OnEnable()
    {
        m_view.RegisterMediator(this);
    }
    public virtual void OnDisable()
    {
        m_view.RemoveMediator(name);
    }

    public abstract IList<string> ListNotificationInterests ();
    public abstract void HandleNotification (INotification<T> notification);

    public virtual void OnRegister() { }
    public virtual void OnRemove() { }
    public virtual string MediatorName
    {
        get { return gameObject.name; }
    }

    private IView m_view;
    public Mediator()
    {
        m_view = View.Instance;
    }
}

對於以上這個Mediator抽象類,直接在OnEnable和OnDisable中寫入了對應的註冊和註銷的方法,因爲這個太常用了,在子類中寫有些不划算;

在看一個最激動人心的吧,泛型Proxy,直接利用對應類型的數據,完全不需要裝箱和拆箱(不過有些情況這樣並不樂觀,比如在一堆接口進行遍歷處理時),大多數據情況下還是很方便的。

其他就不多說了,這個架構已經上傳到Github上了,有興趣的可以參考;

最後是一個使用的小小例子:


using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {
    public Sprite sprite;
    // Use this for initialization
    void Start () {
        Facade.Instance.RegisterCommand <cmd>("cmd");
        Facade.Instance.RegisterProxy(new MyProxy("data","hellow"));
    }

    // Update is called once per frame
    void OnGUI () {
        if (GUILayout.Button("執行commond打印")) {
            Facade.Instance.SendNotification("cmd");
        }
        if (GUILayout.Button("切換圖片")) {
            Facade.Instance.SendNotification<Sprite> ("ImageChange", sprite);
        }
        if (GUILayout.Button("讀取數據包")) {
            MyProxy proxy = Facade.Instance.RetrieveProxy<MyProxy> ("data");
            Debug.Log (proxy.Data);
        }
    }
}
public class MyProxy:Proxy<string>
{
    public MyProxy(string name,string data):base(name,data){}
    public override string Data{get;set;}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章