基于MONO事件派发机制之SendMessage
前言,需要模块划分,那么脚本之间或者对象之间的事件传递是必不可少的。
目标:在之前的一篇文章,以装备面板的设计为例子,想设计结合PureMVC + MONO的一个共同使用,在考虑之前的一些设计想法之后,想单独基于MONO使用事件机制,来处理MONO之间的功能,来独立出MVC框架。
Unity3D 物品系统结合MVC框架设计之装备[1]http://www.unitymanual.com/thread-35823-1-1.html
最后想法是PureMVC中View部分去处理面板结果或者面板需要与其他模块交互的功能 + Mono的事件机制处理面板内部对象之间的消息传递。
1.首先这个脚本不可缺少。
[mw_shl_code=csharp,true]using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class NotificationCenter : MonoBehaviour
{
private static NotificationCenter defaultCenter;
public static NotificationCenter DefaultCenter()
{
if (!defaultCenter)
{
GameObject notificationObject = new GameObject("NotificationCenter");
defaultCenter = notificationObject.AddComponent<NotificationCenter>();
DontDestroyOnLoad(notificationObject);
}
return defaultCenter;
}
Hashtable notifications = new Hashtable();
public void AddObserver(Component observer, String name) { AddObserver(observer, name, null); }
public void AddObserver(Component observer, String name, object sender)
{
if (name == null || name == "") { Debug.Log("Null name specified for notification in AddObserver."); return; }
if (!notifications.ContainsKey(name))
{
notifications[name] = new List<Component>();
}
List<Component> notifyList = (List<Component>)notifications[name];
if (!notifyList.Contains(observer)) { notifyList.Add(observer); }
}
public void RemoveObserver(Component observer, String name)
{
List<Component> notifyList = (List<Component>)notifications[name]; //change from original
if (notifyList != null)
{
if (notifyList.Contains(observer)) { notifyList.Remove(observer); }
if (notifyList.Count == 0) { notifications.Remove(name); }
}
}
public void PostNotification(Component aSender, String aName) { PostNotification(aSender, aName, null); }
public void PostNotification(Component aSender, String aName, object aData) { PostNotification(new Notification(aSender, aName, aData)); }
public void PostNotification(Notification aNotification)
{
if (aNotification.name == null || aNotification.name == "") { Debug.Log("Null name sent to PostNotification."); return; }
List<Component> notifyList = (List<Component>)notifications[aNotification.name];
if (notifyList == null) { Debug.Log("Notify list not found in PostNotification."); return; }
notifyList = new List<Component>(notifyList);
List<Component> observersToRemove = new List<Component>();
foreach (Component observer in notifyList)
{
if (!observer)
{
observersToRemove.Add(observer);
}
else
{
observer.SendMessage(aNotification.name, aNotification, SendMessageOptions.DontRequireReceiver);
}
}
foreach (Component observer in observersToRemove)
{
notifyList.Remove(observer);
}
}
}[/mw_shl_code]
那么来实践一下它是如何监听事件,又是如何派发事件的。
2.监听事件
如图:
public void AddObserver(Component observer, String name)
public void AddObserver(Component observer, String name, object sender)
这两个函数都是监听函数,虽然函数名字不是监听是观察者,个人习惯。
因为是使用Unity3D自带的SendMessage事件机制,所以AddObserver的参数分别为:监听的组件,监听的组件下的脚本函数名。
其外,如果obServer是this,那就这个脚本本身内的函数,如果,是其他的脚本,则是其他脚本的函数。
挂载这个脚本,即是监听了这个脚本下的test的函数。
3.派发事件
public void PostNotification(Component aSender, String aName, object aData)
这个函数的参数分别为:派发的组件,监听的字段名,派发的数据。
对于数据类型,可以使任意类型的数据,因为对于C#,他们所有类型的基类都是object。
外话:
这个地方,AddObserver函数的第三个sender变量,在该函数中没有用到,这里是添加监听对象,第一个变量是,代表监听哪个组件,第二个变量是监听组件上的函数,第三个变量由于没有用到,一开始设计是为了,监听指定哪个组件派发过来的事件(监听事件之后,只要有人派发这个事件,这里就会监听到,假如外面有一万个派发的,但是其实他的目的可能就是想过滤只接受某个组件的派发,那这里就可以起到一个过滤的作用)。这个是可以考虑拓展的。。
缺陷:
因为是使用SendMessage,所监听的事件,必须是继承MonoBehaviour,经测试,不继承是不行的,单独继承Component也不行。
总结:想必对于基于MONO下实现MVC消息机制,使用这一拓展是可以实现的。
其实,我们可以尝试对其结构进行更改,不使用SendMessage,而使用派发Action<T>泛型事件也是可以的,PureMVC底层就是如此。
问题:
对于Unity3D自带的SendMessage来说,它的最大的诟病,是它的效率问题。对于这一问题,可以用Delegate取而代之,据网上说,Delegate的效率10倍与SendMessage。
但是并不是说不能使用SendMessage,毕竟他底层封装了反射机制,使用十分方便,只是不可频繁使用。
下一章节,将使用Delegate去实现【不基于MONO事件派发机制之Delegate】整个源码将在下一章提供。
转载请注明出处。
作者: 大帅纷纭
微博:http://weibo.com/2357191704/profile?topnav=1&wvr=6
博客:http://blog.csdn.net/dashuaifenyun1991
还没有人抢沙发呢~