基于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

    邮箱:bandit_empire@163.com

     

    有帮助就分享一下吧!

    转载请注明:少狼 – 敬畏知识的顽皮狗 » 基于MONO事件派发机制之SendMessage

    喜欢 0

*

还没有人抢沙发呢~