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.youkuaiyun.com/dashuaifenyun1991

邮箱:bandit_empire@163.com




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值