您的位置:首页 > 理论基础 > 数据结构算法

基于MONO事件派发机制之SendMessage

2015-01-27 19:22 176 查看
前言,需要模块划分,那么脚本之间或者对象之间的事件传递是必不可少的。

目标:在之前的一篇文章,以装备面板的设计为例子,想设计结合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
邮箱:bandit_empire@163.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息