泛型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;}
}

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