定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
何时使用:
一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
优点 | 缺点 |
---|---|
1、观察者和被观察者是抽象耦合的。 | 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 |
2、建立一套触发机制。 | 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 |
/ | 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。 |
事件模型的五大组成部分
最为常用的事件模型
说明:事件拥有者是事件响应者的一个字段成员,事件响应者用自己的方法订阅者自己的成员的某个事件。
上述模型C# Demo
using System;
using System.Windows.Forms;
///
/// 实现功能,在一个窗口里有一个文本框和按钮,点击按钮
/// 文本框则显示“Hello World”字符串
///
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
MyForm form = new MyForm();
form.ShowDialog();
}
}
class MyForm : Form
{
private TextBox textBox;
private Button button;
public MyForm()
{
this.textBox = new TextBox(); // 事件响应者textBox
this.button = new Button(); // 事件拥有者button 事件:Click
// 让这两个控件显示在窗口里
this.Controls.Add(this.textBox);
this.Controls.Add(this.button);
this.button.Click += this.ButtonClicked;//事件订阅
// 设置button控键
this.button.Text = "Say Hello";
this.button.Top = 50;
}
///
/// 事件处理器是ButtonClicked方法
///
private void ButtonClicked(object sender, EventArgs e)
{
this.textBox.Text = "Hello World";
}
}
}
目标:定义事件的观察者,实现观察者模式。
unity处设置不再赘述
C#代码部分
BaseUnit.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum DamageType
{
Normal,
Critical
}
public enum HpShowType
{
Null,
Damage,
Miss
}
public class BaseUnit : MonoBehaviour
{
public delegate void SubHpHandler(BaseUnit source, float subHp, DamageType damageType, HpShowType showType);
public event SubHpHandler OnSubHp;
protected virtual void OnBeAttacked(float harmNumber, bool isCritical, bool isMiss)
{
DamageType damageType = DamageType.Normal;
HpShowType showType = HpShowType.Damage;
if (isCritical)
damageType = DamageType.Critical;
if (isMiss)
showType = HpShowType.Miss;
// 首先判断是否有方法订阅了该事件,如果有则通知它们
if (OnSubHp != null)
OnSubHp(this, harmNumber, damageType, showType);
}
public bool IsHero
{
get { return true; }
}
public void BeAttacked()
{
float possibility = UnityEngine.Random.value;
bool isCritical = UnityEngine.Random.value > 0.5f;
bool isMiss = UnityEngine.Random.value > 0.5f;
float harmNumber = 10000f;
OnBeAttacked(harmNumber, isCritical, isMiss);
}
}
BattleInformationComponent.cs
using System;
using UnityEngine;
public class BattleInformationComponent : MonoBehaviour
{
public BaseUnit unit;
private void Start()
{
this.unit = gameObject.GetComponent<BaseUnit>();
this.AddListener();
}
// 订阅BaseUnit定义的事件OnSubHp
private void AddListener()
{
this.unit.OnSubHp += this.OnSubHp;
}
// 取消对BaseUnit定义的事件OnSubHp的订阅
private void RemoveListener()
{
// 注销关注
this.unit.OnSubHp -= this.OnSubHp;
}
// 当BaseUnit 被攻击时,会调用该回调事件
private void OnSubHp( BaseUnit source, float subHp, DamageType damageType, HpShowType showType)
{
string unitName = string.Empty;
string missStr = "闪避";
string damageTypeStr = string.Empty;
string damageHp = string.Empty;
if(showType == HpShowType.Miss)
{
Debug.Log(missStr);
return;
}
if (source.IsHero)
{
unitName = "英雄";
}
else
{
unitName = "士兵";
}
damageTypeStr = damageType == DamageType.Critical ? "暴击" : "普通攻击";
damageHp = subHp.ToString();
Debug.Log(unitName + damageTypeStr + damageHp);
}
}
Controller.cs
using System;
using UnityEngine;
public class Controller : MonoBehaviour
{
public BaseUnit unit;
private void OnGUI()
{
if( GUI.Button(new Rect(10, 10, 150, 100), "攻击测试" ))
{
this.unit.BeAttacked();
}
}
}
public delegate void SubHpHandler(BaseUnit source, float subHp, DamageType damageType, HpShowType showType);
public event SubHpHandler OnSubHp;
使用event关键字来定义一个事件成员,每个事件成员需要指定以下3项内容:
private void OnSubHp( BaseUnit source, float subHp, DamageType damageType, HpShowType showType)
{
//DoSomething
}
if (OnSubHp != null)
OnSubHp(this, harmNumber, damageType, showType);
大家能从上例中找出事件的五大组成部分吗,另外观察者模式也通过C#的事件模型实现啦。
https://www.bilibili.com/video/av1422127?p=21
书籍:Unity3D脚本编程 陈嘉栋著
更多: