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
转载请注明:少狼 – 敬畏知识的顽皮狗 » Unity3D事件派发机制之Delegate
还没有人抢沙发呢~