在Unity3D中基于订阅者模式怎样实现事件机制

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Unity3D中基于订阅者模式怎样实现事件机制相关的知识,希望对你有一定的参考价值。

参考技术A 我们知道通过在Unity3D中通过GetComponent就可以获得某个模块的实例,进而引用这个实例完成相关任务的调用。可是显然这种方法,就像我们随身带着现金去和不同的人进行交易,每次交易的时候都需要我们考虑现金的支入和支出问题,从安全性和耦合度两个方面进行考虑,这种方法在面对复杂的系统设计的时候,非常容易造成模块间的相互依赖,即会增加不同模块间的耦合度。为了解决这个问题,大家开始考虑单例模式,因为单例模式能够保证在全局内有一个唯一的实例,所以这种方式可以有效地降低模块间的直接引用。单例模式就像是我们在银行内办理了一个唯一的账户,这样我们在交易的时候只需要通过这个账户来进行控制资金的流向就可以了。单例模式确保了各个模块间的独立性,可是单例模式更多的是一种主动行为,即我们在需要的时候主动去调用这个模块,单例模式存在的问题是无法解决被调用方的反馈问题,除非被调用方主动地去调用调用方的模块实例。说到这里我们好像看到了一种新的模式,这就是我们下面要提到的事件机制。
订阅者模式和事件机制

首先这里要提到一种称为“订阅者模式”的设计模式,这种设计模式在《大话设计模式》这本书中称为“观察者模式”或者“发布-订阅(Publish/Subscribe)模式”,我们这里暂且叫做“订阅者模式”吧!该模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个对象在状态发生变化时会通知所有观察者对象,使它们能够自动更新自己。针对这个模式,我们可以考虑事件机制的实现,事件机制可以理解为在一个事件中心(Subject)保存有对所有事件(Observer)的引用,事件中心负责对这些事件进行分发,这样每个事件就可以通过回调函数的方式进行更新,这样就实现了一个事件机制。下面给出基本的代码实现:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace UniEventDispatcher

/// <summary>
/// 定义事件分发委托
/// </summary>
public delegate void OnNotification(Notification notific);

/// <summary>
///通知中心
/// </summary>
public class NotificationCenter


/// <summary>
/// 通知中心单例
/// </summary>
private static NotificationCenter instance=null;
public static NotificationCenter Get()

if(instance == null)
instance = new NotificationCenter();
return instance;

return instance;


/// <summary>
/// 存储事件的字典
/// </summary>
private Dictionary<string,OnNotification> eventListeners
= new Dictionary<string, OnNotification>();

/// <summary>
/// 注册事件
/// </summary>
/// <param name="eventKey">事件Key</param>
/// <param name="eventListener">事件监听器</param>
public void AddEventListener(string eventKey,OnNotification eventListener)

if(!eventListeners.ContainsKey(eventKey))
eventListeners.Add(eventKey,eventListener);



/// <summary>
/// 移除事件
/// </summary>
/// <param name="eventKey">事件Key</param>
public void RemoveEventListener(string eventKey)

if(!eventListeners.ContainsKey(eventKey))
return;

eventListeners[eventKey] =null;
eventListeners.Remove(eventKey);


/// <summary>
/// 分发事件
/// </summary>
/// <param name="eventKey">事件Key</param>
/// <param name="notific">通知</param>
public void DispatchEvent(string eventKey,Notification notific)

if (!eventListeners.ContainsKey(eventKey))
return;
eventListeners[eventKey](notific);


/// <summary>
/// 分发事件
/// </summary>
/// <param name="eventKey">事件Key</param>
/// <param name="sender">发送者</param>
/// <param name="param">通知内容</param>
public void DispatchEvent(string eventKey, GameObject sender, object param)

if(!eventListeners.ContainsKey(eventKey))
return;
eventListeners[eventKey](new Notification(sender,param));


/// <summary>
/// 分发事件
/// </summary>
/// <param name="eventKey">事件Key</param>
/// <param name="param">通知内容</param>
public void DispatchEvent(string eventKey,object param)

if(!eventListeners.ContainsKey(eventKey))
return;
eventListeners[eventKey](new Notification(param));


/// <summary>
/// 是否存在指定事件的监听器
/// </summary>
public Boolean HasEventListener(string eventKey)

return eventListeners.ContainsKey(eventKey);




注意到在这个“通知中心”中,我们首先实现了单例模式,这样我们可以通过Get方法来获取该“通知中心”的唯一实例,其次这里利用一个字典来存储对所有事件的引用,这样保证外部可以通过AddEventListener和RemoveEventListener这两个方法来进行事件的添加和移除,对于添加的事件引用我们可以通过DispatchEvent方法来分发一个事件,事件的回调函数采用委托来实现,注意到这个委托需要一个Notification类型,对该类型简单定义如下:
using System;
using UnityEngine;

namespace UniEventDispatcher

public class Notification

/// <summary>
/// 通知发送者
/// </summary>
public GameObject sender;

/// <summary>
/// 通知内容
/// 备注:在发送消息时需要装箱、解析消息时需要拆箱
/// 所以这是一个糟糕的设计,需要注意。
/// </summary>
public object param;

/// <summary>
/// 构造函数
/// </summary>
/// <param name="sender">通知发送者</param>
/// <param name="param">通知内容</param>
public Notification(GameObject sender, object param)

this.sender = sender;
this.param = param;


/// <summary>
/// 构造函数
/// </summary>
/// <param name="param"></param>
public Notification(object param)

this.sender = null;
this.param = param;


/// <summary>
/// 实现ToString方法
/// </summary>
/// <returns></returns>
public override string ToString()

return string.Format("sender=0,param=1", this.sender, this.param);


以上是关于在Unity3D中基于订阅者模式怎样实现事件机制的主要内容,如果未能解决你的问题,请参考以下文章

Spring中的观察者模式(发布订阅模式)(基于SpringBoot实现)

利用zookeeper的发布/订阅模式实现配置动态变更

架构设计:系统存储(16)——Redis事件订阅和持久化存储

Redis事件订阅和持久化存储

C# WPF MVVM模式Prism框架下事件发布与订阅

C# WPF MVVM模式Caliburn.Micro框架下事件发布与订阅