观察者模式和委托

来源:互联网 发布:数据库系统设计 编辑:程序博客网 时间:2024/06/13 09:15

                                                                                                         观察者模式和委托

1.聊聊委托

委托就是说委托分为发布者和监听者,发布者就是说谁执行这个委托的方法,谁就是发布者,

而谁监听这个委托的方法,谁就是监听者。

比如说我们当点击一个箱子的时候,让它做相应的事件。在一个箱子上公布了一个委托,

那么这个 箱子就是发布者,而这个箱子并不知道要做什么,那么谁去注册了这个委托,

当我们点击这个箱子的时候,就会执行相应的注册方法。


委托用+=表示可以监听多个委托,如果用=的话只能监听一个委托。

所以一般监听用+=。

委托的使用,如果在某个类中某个方法执行的同时需要通知其他类,我们可以在这个类中

写一个委托,在其他类的Start方法中进行注册,在OnDestroy进行解除委托。

2.聊聊观察者模式

观察者核心是委托。

先看客户端,如果从服务器收到的数据,我是通过socket网络模块发给我的业务逻辑,发给我

客户端的各个模块,这个时候我们就要用观察者来把这个数据发送给客户端,

下面通过一个例子,说一下观察者模式:

小明下班了,需要通知他的老婆,兄弟,boss。对于这个需求我们怎么通过代码去实现呢?

这个时候我们只需要让小明发布一个委托,然后在小明下班的方法里面,调这个委托,然后老婆,

兄弟,boss需要去监听小明下班,所以需要在这三个人这里去注册一下这个方法。




小明里面定义的委托

public delegate void XiaoMingXiaBanHandle();

但是我如果想知道几点下班,我们可以往委托里面加个参数,如下

Public delegate void XiaoMingXiaBanHandle(int time);

我们在上面只是做了小明下班的动作,然后让其他人去监听小明下班,但是小明可不只有下班这一个动作,

他还有很多动作,比如我们现在把需求修改成这样,他有上班和下班,他上班的时候,他的老板会知道,

别人不知道,而他下班的时候,这些人都知道,那他的动作就有两个了,那我们怎么做呢?

我们需要再定义一个委托原型,但是如果他的动作太多的话,你定义很多委托就不合适了,

所以我们修改一下委托,把原型修改一下,如下

Public delegate void OnActionHandle(ushort actionID,params object[] param);

参数数组,可以往里面传很多参数。我们这个委托actionID表示动作,后面表示动作的参数;

比如说上班我们用1表示,后面比如说传一个时间,表示上班时间。(1,9

我们可以在上班的时侯,调用这个委托,在其他监听的对象里面去注册委托,

每个注册委托,可以根据我们定义的actionID去判断,是哪个动作。

比如private void OnShangBan(ushort actionID,object[] param)

{

If(actionID==1)

{

Debug.Log(“上班时间到了”);

}

我们这个朋友圈是一个中间机构,但是呢,比如我发一个动作,我只想要让特定的人知道,

不想让所有人都知道,那应该去怎么解决这个问题啊?

小明里面定义的委托

public delegate void XiaoMingXiaBanHandle();

但是我如果想知道几点下班,我们可以往委托里面加个参数,如下

   public delegate void XiaoMingXiaBanHandle(int time);

我们在上面只是做了小明下班的动作,然后让其他人去监听小明下班,但是小明可不只有下班这一个动作,

他还有很多动作,比如我们现在把需求修改成这样,他有上班和下班,他上班的时候,他的老板会知道,

别人不知道,而他下班的时候,这些人都知道,那他的动作就有两个了,那我们怎么做呢?

我们需要再定义一个委托原型,但是如果他的动作太多的话,你定义很多委托就不合适了,所以我们修

改一下委托,把原型修改一下,如下

public delegate void OnActionHandle(ushort actionID,params object[] param);

参数数组,可以往里面传很多参数。我们这个委托actionID表示动作,后面表示动作的参数;

比如说上班我们用1表示,后面比如说传一个时间,表示上班时间。(1,9

我们可以在上班的时侯,调用这个委托,在其他监听的对象里面去注册委托,每个注册委托,可以根据我

们定义的actionID去判断,是哪个动作。

比如

private void OnShangBan(ushort actionID,object[] param)

{

 if(actionID==1)

{

Debug.Log("上班时间到了");

}

 

我们这个朋友圈是一个中间机构,但是呢,比如我发一个动作,我只想要让特定的人知道,不想让所有人都知道,那应该去怎么解决这个问题啊?

 

我们再去回到委托原型啊,对其修改成

public delegate void OnActionHandle(params object[] param);

我们加一个字典 ,以动作编号为Id,关注这个动作的所有委托做值,也就是说一个委托的集合,

private Dictionary<ushort,List<OnActionHandle>> dic=new Dictionary<ushort,List<OnActionHandle>>();

///添加监听监听者在初始化的时候调用 监听某个动作

public void AddEventListener(ushort actionID,OnActionHandle handle )

{

//先判断编号是否在字典中,如果在字典中,直接添加

if(dic.ContainsKey(actionID))

{

dic[actionID].Add(handle);

}

Else

{

//不存在先创建集合,然后往集合里面添加集合

List<OnActionHandle> listHandle=new List<OnActionHandle>();

List.Add(handle);

dic[actionID]=listHandle;

}

}

 

//移除监听 监听者在OnDestroy的时候调的,不想监听的时候移除

public void RemoveEventListener(ushort actionID,OnActionHandle handle)

{

//如果字典里存在该键actionID,找到对应的委托集合,可以移除hanle

If(dic.ContainsKey(actionID))

{

List<OnActionHandle> listHandle=dic[actionID];

listHandle.Remove(handle);

 

//如果集合个数为0,从字典里移除该key

if(listHadle.Count==0)

{

dic.remove(actionID);

}

}

}

 

//派发消息,就是发布者调的方法 只把这个消息派发给监听我这个动作id的人

public void Despatch(ushot actionID,params object[]params)

{

//首先先去字典里去找是否有这个键

if(dic.ContainsKey(actionID))

{

//找到对应的集合

List<OnActionHandl> listHandle=dic[actionID];

//判断集合的个数如果大于0

if(listHandle.Count>0)

{

//遍历集合,执行委托

for(int i=0;i<=listHandle.Count;i++)

{

if(listHande[i]!=null)

{listHandle[i](param);}

}

}

}

 

 

我们写观察者的目的一是为了调用方便,二是为了客户端发消息的时候,让服务器去监听。

客户端有了观察者之后,服务器也得有观察者。当然可能和客户端不太一样,还得去修改委托的参数,但是原理是一样的。

下面是根据需求写的观察者工具类

using System.Collections.Generic;

using UnityEngine;

using System;

 

public class EventDispatcher : Singleton<EventDispatcher> {

 

//委托

public delegate void OnActionHandle(byte[] buffer);

//一个id对应一个监听队列,一件事情可以有多个监听对象

private Dictionary<ushort,List<OnActionHandle>> dic =new Dictionary<ushort, List<OnActionHandle>> ();

 

/// <summary>

/// 注册监听,监听某个动作,在监听者的初始化方法中注册监听

/// </summary>

/// <param name="protoID">Proto I.</param>

/// <param name="handle">Handle.</param>

public void AddEventListener(ushort protoID,OnActionHandle handle)

{

if (dic.ContainsKey (protoID)) {

dic [protoID].Add (handle);

} else {

List<OnActionHandle> listHandle = new List<OnActionHandle> ();

listHandle.Add (handle);

dic [protoID] = listHandle;

}

}

 

 

/// <summary>

/// 移除监听,在对象销毁的时候去移除

/// </summary>

/// <param name="protoID">Proto I.</param>

/// <param name="handle">Handle.</param>

public void RemoveEventListener(ushort protoID,OnActionHandle handle)

{

if (dic.ContainsKey (protoID)) {

List<OnActionHandle> listHandle = dic [protoID];

dic [protoID].Remove (handle);

 

if (listHandle.Count == 0) {

dic.Remove (protoID);

}

}

}

 

/// <summary>

/// 派发消息发布委托的这边调用的

/// </summary>

public void DisPatched(ushort protoID,byte[] buffer)

{

if (dic.ContainsKey (protoID)) {

List<OnActionHandle> listHandle = dic [protoID];

if (listHandle.Count > 0) {

for (int i = 0; i < listHandle.Count; i++) {

if (listHandle [i] != null) {

listHandle [i](buffer);

}

}

}

}

}

}

 




原创粉丝点击