Unity3D设计模式之观察者模式(16)(一)

来源:互联网 发布:小白软件库 编辑:程序博客网 时间:2024/05/22 11:52

首先这里要提到一种称为“观察者模式”的设计模式,这种设计模式在《大话设计模式》这本书中称为“观察者模式”或者“发布-订阅(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);
}
}
}

使用事件机制的一个示例

这里以一个简单的示例来验证事件机制的可行性,我们在场景中有一个球体,默认这个球体的颜色为白色,通过调整界面中的RGB数值,可以改变球体的颜色,在这个示例中UI是事件发送者,负责UI中Slider控件的数值发生变化时向球体发送消息,传递的数据类型是Color类型;球体为事件接收者,负责注册事件及接收到消息后的处理。因为代码较为简单,所以这里写在一个脚本中:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UniEventDispatcher;

public class Example : MonoBehaviour
{
/// <summary>
/// R数值的Slider
/// </summary>
private Slider sliderR;

/// <summary>
/// G数值的Slider
/// </summary>
private Slider sliderG;

/// <summary>
/// B数值的Slider
/// </summary>
private Slider sliderB;

private  Button bu;
Slider sliderh;

void Start ()
{
//在接收者中注册事件及其回调方法
NotificationCenter.Get().AddEventListener("ChangeColor", ChangeColor);


//在发送者中分发事件,这里以UI逻辑为例
sliderR = GameObject.Find("Canvas/SliderR").GetComponent<Slider>();
sliderG = GameObject.Find("Canvas/SliderG").GetComponent<Slider>();
sliderB = GameObject.Find("Canvas/SliderB").GetComponent<Slider>();
//注册UI事件
sliderR.onValueChanged.AddListener(OnValueChanged);
sliderG.onValueChanged.AddListener(OnValueChanged);
sliderB.onValueChanged.AddListener(OnValueChanged);
}

public void OnValueChanged(float value)
{
//获得RGB数值
float r = sliderR.value;
float g = sliderG.value;
float b = sliderB.value;
//分发事件,注意和接收者协议一致
NotificationCenter.Get().DispatchEvent("ChangeColor", new Color(r, g, b));
}

/// <summary>
/// 改变物体材质颜色
/// </summary>
/// <param name="notific"></param>
public void ChangeColor(Notification notific)
{
Debug.Log(notific.ToString());
//设置颜色
this.transform.GetComponent<Renderer>().material.color = (Color)notific.param;
}
}

该示例运行效果如下:


项目工程地址:

http://download.csdn.net/detail/u011480667/9922790

实用型的案例见下: