Unity3D事件派发机制之Delegate

    上一章:【基于MONO事件派发机制之SendMessage】

    废话不多说,直接上代码。

    [mw_shl_code=csharp,true]/*
    * NotificationDelegCenter
    * 使用代理监听和派发事件
    * 相对SendMessage使用delegate,提高了消息派发效率
    * author : 大帅纷纭
    */

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using System;

    //C#在类定义外可以声明方法的签名(Delegate,代理或委托),但是不能声明真正的方法。
    public delegate void OnNotificationDelegate(Notification note);

    public class NotificationDelegCenter
    {
        private static NotificationDelegCenter instance = null;

        private Dictionary<string, OnNotificationDelegate> eventListerners = new Dictionary<string, OnNotificationDelegate>();

        //Single 
        public static NotificationDelegCenter getInstance()
        {
            if (instance == null)
            {
                instance = new NotificationDelegCenter();
                return instance;
            }
            return instance;
        }

        /*
         * 监听事件
         */

        //添加监听事件
        public void addEventListener(string type, OnNotificationDelegate listener)
        {
            if (!eventListerners.ContainsKey(type))
            {
                OnNotificationDelegate deleg = null;
                eventListerners[type] = deleg;
            }
            eventListerners[type] += listener;
        }

        //移除监听事件
        public void removeEventListener(string type, OnNotificationDelegate listener)
        {
            if (!eventListerners.ContainsKey(type))
            {
                return;
            }
            eventListerners[type] -= listener;
        }

        //移除某一类型所有的监听事件
        public void removeEventListener(string type)
        {
            if (eventListerners.ContainsKey(type))
            {
                eventListerners.Remove(type);
            }
        }

        /*
         * 派发事件
         */ 

        //派发数据
        public void dispatchEvent(string type, Notification note)
        {
            if (eventListerners.ContainsKey(type))
            {
                eventListerners[type](note);
            }
        }

        //派发无数据
        public void dispatchEvent(string type)
        {
            dispatchEvent(type, null);
        }

        //查找是否有当前类型事件监听
        public Boolean hasEventListener(string type)
        {
            return eventListerners.ContainsKey(type);
        }
    }[/mw_shl_code]
    这类事件处理中心,是基于Delegate代理机制,并不需要使用sendMessage来发送事件,对于事件内部的处理,还有更多的扩展可能,例如我直接写个接口让外界拿到代理。 

    数据部分:

    [mw_shl_code=csharp,true]using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using UnityEngine;

    public class Notification
    {
        public Component sender;
        public String name;
        public object data;

        public Notification(Component aSender, String aName) { sender = aSender; name = aName; data = null; }
        public Notification(Component aSender, String aName, object aData) { sender = aSender; name = aName; data = aData; }
    }[/mw_shl_code]
    这是一个传输数据的类,格式可自行定义,例如Component可以不需要,这个可以自行定制。这个和前一篇的数据是一样的。

    测试例子:

    [mw_shl_code=csharp,true]using UnityEngine;
    using System.Collections;

    public class TestDeleg : MonoBehaviour {

    // Use this for initialization
    void Start ()
        {
            NotificationDelegCenter.getInstance().addEventListener("ceshi", testFun);
            NotificationDelegCenter.getInstance().addEventListener("ceshi", new testNoMono().test);//其他没有继承mono的类对象
            NotificationDelegCenter.getInstance().addEventListener("ceshi", testFun1);
    }
            
        public void testFun(Notification note)
        {
            Debug.Log("派发过来的数据------" + note.sender);
            Debug.Log("派发过来的数据------" + note.name);
            Debug.Log("派发过来的数据------" + note.data);

         // NotificationDelegCenter.getInstance().removeEventListener("ceshi", testFun);
        // NotificationDelegCenter.getInstance().removeEventListener("ceshi");
        }

        public void testFun1(Notification note)
        {
            Debug.Log("派发过来的数据-1-----" + note.sender);
            Debug.Log("派发过来的数据-1-----" + note.name);
            Debug.Log("派发过来的数据-1-----" + note.data);
        }

        public void dispFun()
        {
            NotificationDelegCenter.getInstance().dispatchEvent("ceshi", new Notification(this, "自己", "这是一个数据"));
        }
    }
    [/mw_shl_code]

    结果可以的。

    拓展:
    对于这个这个事件,包括上一篇的sendMessage都使用单例模式,其实,这个也是不一定的,如果是个单例的话,就意味着它只有一个实例,所有的事件都会存储在事件中心的字典里,这样有很多不好的地方。
    1.事件过多,事件转发处理数据可以能会变慢,主要在查询部分。
    2.对于游戏来说,模块划分的重要性也是如此,每个模块的事件都存储在同一个地方非常不好。
    其他自行脑补。。。

    那么就不要设置成单例就好了。。。

    每个单独的模块定义一个事件中心的实例,来处理自家的事情,外界干扰不了。这样每个模块的事件就独立开来了。

    那么模块之间也可能存在一些事件需要通信的呢?

    那我们就给外界留一个可以获取到我们实例的接口就好了。你要你就来拿,但是没必要我们的事件都在一起对吧。

    是的,这样就可以避免了。

    [mw_shl_code=csharp,true]public class NotificationDelegCenters
    {
        private Dictionary<string, OnNotificationDelegate> eventListerners;

        public NotificationDelegCenters()
        {
            eventListerners = new Dictionary<string, OnNotificationDelegate>();
        }
    }[/mw_shl_code]

    在用法上,我们随时都可以声明实例(你可以选择一个面板的Manager类直接继承,或者实例一个对象),这就要看你怎么去分模块了,不是什么事件处理都去实例化新的代理中心对象,最好的方式就是每一个模块实例一个,这样模块内部所有的消息都单独存在这个实例当中。

    例如:
    在登陆模块打开注册面板这一流程中,登陆,发一个事件过去告诉注册说,我要打开你的面板,那好注册就把自己的面板打开,这一流程中,并不是登陆去打开注册面板,而是登陆告诉注册去打开注册面板,这一功能是注册干的活,登陆可能他都不知道注册干了什么,很可能注册它屁也没干,但是对于登陆来说,我告诉你了该干啥,不怪我?当然,这是一个模块内的分离,延伸到登陆到场景的转换思想也是如此,这样就属于两个模块之间的消息处理了。【如果有人说我可以直接使用mono挂载对象,是的,当然可以没错】。

    一切回顾起来其实很简单,但是,寻求或者说思考为何如此的过程,是我们提升的良药。ps : 高手不要打击我,我怕、

    转载请注明出处。

    作者: 大帅纷纭

    微博:http://weibo.com/2357191704/profile?topnav=1&wvr=6

    博客:http://blog.csdn.net/dashuaifenyun1991

    邮箱:bandit_empire@163.com

     

    有帮助就分享一下吧!

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

    喜欢 2

*

还没有人抢沙发呢~