一.介绍
观察者模式是一种软件设计模式,它允许对象之间定义一对多的依赖关系,当一个对象状态发生变化时,所有依赖于它的对象都会得到通知并被自动更新。这种模式可以有效地解耦主题和观察者之间的依赖关系,提高系统的灵活性和可维护性。
在观察者模式中,主题和观察者是独立的实体。主题负责维护一个观察者列表,并通知所有的观察者关于状态的变化。观察者负责监听主题的状态变化,并在收到通知时更新自己的状态。具体观察者则是观察者的子类,它实现了更新自己状态的具体逻辑。
在游戏开发中,观察者模式可以用于实现多种功能。例如,在角色状态变化方面,我们可以将多个监听器绑定到同一个事件上,当事件发生时,所有监听器都会收到通知并执行相应的操作。例如,当角色血量发生变化时,所有绑定到该事件的监听器都会收到通知,并执行相应的操作,如播放声音、更新UI等。
二.实现
设置一个管理类来控制事件订阅注册与注销。
EventCenter订阅管理器
csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class EventCenter
{
private static EventCenter instance;//EventCenter使用单例模式
private Dictionary<string,IEventInfo> _eventDic = new Dictionary<string, IEventInfo>();//创建事件字典(事件名,订阅列表)
public static EventCenter Instance
{
get{
if(instance == null)
{
instance = new EventCenter();
}
return instance;
}
}
public void AddEventListener(string name,UnityAction action)//添加订阅消息
{
if(_eventDic.ContainsKey(name))//事件名是否存在
{
(_eventDic[name] as EventInfo).actions+=action;//存在,向该事件名的订阅列表添加该action
}
else
{
_eventDic.Add(name,new EventInfo(action));//不存在,创建新的事件名和订阅列表
}
}
public void EventTrigger(string name) //通知信息
{
if(_eventDic.ContainsKey(name))//判断是否存在事件名
{
if((_eventDic[name] as EventInfo).actions != null)//该事件名是否有action订阅
{
(_eventDic[name] as EventInfo).actions.Invoke();//通知所有订阅该时间的action
}
}
}
public void RemoveEventListener(string name,UnityAction action)//取消订阅
{
if(_eventDic.ContainsKey(name))//判断是否存在事件名
{
(_eventDic[name] as EventInfo).actions -= action;//取消该事件下的action订阅
}
}
public void AddEventListener<T>(string name,UnityAction<T> action)//和上面函数功能一致,可携带参数
{
if(_eventDic.ContainsKey(name))
{
(_eventDic[name] as EventInfo<T>).actions+=action;
}
else
{
_eventDic.Add(name,new EventInfo<T>(action));
}
}
public void EventTrigger(string name)
{
if(_eventDic.ContainsKey(name))
{
if((_eventDic[name] as EventInfo<T>).actions != null)
{
(_eventDic[name] as EventInfo<T>).actions.Invoke();
}
}
}
public void RemoveEventListener(string name,UnityAction action)
{
if(_eventDic.ContainsKey(name))
{
(_eventDic[name] as EventInfo<T>).actions -= action;
}
}
public void Clear()//清空所有订阅
{
_eventDic.Clear();
}
}
public interface IEventInfo //创建接口,让类继承接口来实现便于实现多中类型订阅列表
{
}
public class EventInfo:IEventInfo //不带参数的订阅列表
{
public UnityAction actions;
public EventInfo(UnityAction action)
{
actions += action;
}
}
public class EventInfo<T>:IEventInfo //带参数的订阅列表,使用了泛型,可以传递多种数据类型的参数
{
public UnityAction<T> actions;
public EventInfo(UnityAction<T> action)
{
actions += action;
}
}
添加订阅事件
csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager : MonoBehaviour
{
public PlayerStatBar playerStatBar;//角色血量
private void Start()
{
EventCenter.Instance.AddEventListener("EventTakeDamage",OnHealthEvent)
}
private void OnHealthEvent(Character character)//获取角色当前的血量与最大血量比,并调用playerStatBar.OnHealthChange,更新血量UI
{
var persentage = character.currentHP / character.maxHP;
playerStatBar.OnHealthChange(persentage);
}
}
触发事件
csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Character : MonoBehaviour
{
public void TakeDamage(Attack attacker)//触发受伤
{
EventCenter.instance.EventTrigger<Character>("EventTakeDamage",this);//触发消息
}
}
三.优缺点
优点:
解耦:观察者模式可以有效地解耦主题和观察者之间的依赖关系,使得主题和观察者可以独立地变化和发展,提高了系统的灵活性和可维护性。
自动通知:当主题状态发生变化时,所有的观察者都会自动收到通知,从而可以及时地更新自己的状态,避免了手动更新和维护的麻烦。
消息传递透明:观察者模式使用事件/消息机制实现主题和观察者之间的通信,这种机制使得消息传递过程变得透明,易于理解和维护。
缺点:
性能开销:观察者模式需要维护一个观察者列表,并在主题状态发生变化时通知所有的观察者,这可能会导致一定的性能开销。
复杂性:观察者模式涉及多个对象的交互和依赖关系,这可能会增加系统的复杂性和维护难度。