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