訂閱者模式和事件機制
首先這裏要提到壹種稱為“訂閱者模式”的設計模式,這種設計模式在《大話設計模式》這本書中稱為“觀察者模式”或者“發布-訂閱(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);
}
}
}