一、观察者模式
1.1 观察者模式定义
意图: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变是,所有依赖于它的对象都能得到通知并自动更新。
适用性:
- 当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
- 当应用中的一些对象对象观察其他对象时,可以使用此模式。订阅列表是动态的,因此订阅者可随时会加入或离开此列表。
1.2 观察者模式结构
-
发布者:会向其他对象发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。
当新事件发生时, 发送者会遍历订阅列表并调用每个订阅者对象的通知方法。 该方法是在订阅者接口中声明的。
-
订阅者: 接口声明了通知接口。 在绝大多数情况下, 该接口仅包含一个 update更新方法。 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息。
-
具体订阅者: 可以执行一些操作来回应发布者的通知。 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。
订阅者通常需要一些上下文信息来正确地处理更新。 因此, 发布者通常会将一些上下文数据作为通知方法的参数进行传递。 发布者也可将自身作为参数进行传递, 使订阅者直接获取所需的数据。
-
客户端 :会分别创建发布者和订阅者对象, 然后为订阅者注册发布者更新。
二、实例
实现思路
- 声明订阅者接口。 该接口声明一个通知方法。
- 声明发布者接口并定义一些接口来在列表中添加和删除订阅对象。
- 创建具体发布者类。 每次发布者发生了重要事件时都必须通知所有的订阅者。
- 在具体订阅者类中实现通知更新的方法。
1.Monster
public class Monster : MonoBehaviour
{public string sname = "怪物x";// Start is called before the first frame updatevoid Start(){Invoke("Dead",1);}void Dead(){Debug.Log("怪物死亡!");//GameObject.Find("Player").GetComponent<Player>().MonsterDead(this);//GameObject.Find("Task").GetComponent<Task>().TaskmonsterDead(this);//GameObject.Find("Other").GetComponent<Other>().OthermonsterDead(this);EventCenter.GetInstance().EventTrigger("MonsterDead",this);}
}
2.Player
void Start()
{ EventCenter.GetInstance().AddEventListener("MonsterDead", MonsterDeadDo);
}public void MonsterDeadDo(object info)
{Debug.Log("玩家的奖励"+ (info as Monster).name);
}void OnDestory()
{EventCenter.GetInstance().RemoveEventListener("MonsterDead", MonsterDeadDo);
}
3.EventCenter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;/// <summary>
/// 事件中心 单例模式对象
/// 1.dictionary
/// 2.委托
/// 3.观察者设计模式
/// </summary>
public class EventCenter : Singleton<EventCenter>
{//使用泛型委托传递怪物-蝙蝠等 具体敌人类型public Dictionary<string, UnityAction<object>> eventDic = new Dictionary<string, UnityAction<object>>();/// <summary>/// 添加事件监听/// </summary>/// <param name="name">事件的名字</param>/// <param name="action">准备用来处理事件的 委托函数</param>public void AddEventListener(string name,UnityAction<object> action){//判断事件中心是否有此 函数if (eventDic.ContainsKey(name))eventDic[name] += action;//无elseeventDic.Add(name, action);}/// <summary>/// 执行函数/// </summary>/// <param name="name">事件名</param>/// <param name="info">传递参数 具体怪物类型</param>public void EventTrigger(string name,object info){//判断触发中心是否有此 函数if (eventDic.ContainsKey(name)){eventDic[name](info);}}/// <summary>/// 移除对应事件监听/// </summary>/// <param name="name">事件名</param>/// <param name="action">委托函数</param>public void RemoveEventListener(string name, UnityAction<object> action){//判断事件中心是否有此 函数if (eventDic.ContainsKey(name))eventDic[name] -= action;}/// <summary>/// 清空事件中心,主要用于场景切换/// </summary>public void Clear(){eventDic.Clear();}
}