由於前期項目需要,在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;}
}