提示:个人学习总结,如有错误,尽请指正
让代码宣称有趣的事情发生了,而不必关心到底是谁接受了通知。
事件与其他对象行为的解耦,如成就系统在什么时候响应成就,如果不小心就把代码写在很多奇怪的地方,而我们要做的就是让物理代码去声称“不知道有谁感兴趣,但是这个事情发生了”,成就系统接收到声称再去处理;再如社区通知打疫苗,居民打疫苗不应该由社区调用,而是居民收到通知后自己决定。
//TODO
它有两个任务。首先,它有一个列表,保存默默等它通知的观察者;然后就是发送通知
using System.Collections.Generic;
public abstract class Notifier
{
private IList<Observer> observers = new List<Observer>();
//添加观察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除观察者
public void Detach(Observer observer)
{
observers.Remove(observer);
}
public void Notify()
{
foreach (var item in observers)
{
item.Update();
}
}
}
为所有具体观察者定义一个接口,在得到通知时更新自己
抽象观察者一般用一个抽象类或者接口实现,更新接口通常包含一个Update方法(更新方法)
public abstract class Observer
{
public abstract void Update();
}
内部状态改变时,给所有登记过的观察者发出通知。
广播
public class Radio : Notifier
{
private string state;
public string State { get; set; }
}
具体观察者可以保存一个指向具体主题对象的引用
using UnityEngine;
//射手
public class Shooter : Observer
{
private Radio radio;
public Shooter (Radio radio)
{
this.radio = radio;
}
public override void Update()
{
Debug.Log("shoot now!");
}
public Radio Subject
{
get{ return radio; }
set{ radio = value; }
}
}
添加观察者,发送通知
using UnityEngine;
public class ObserveGame : MonoBehaviour
{
private void Start()
{
Radio radio = new Radio();
radio.Attach(new Shooter(radio, "1"));
radio.Attach(new Shooter(radio, "2"));
radio.State = "boom";
radio.Notify();
}
}
using UnityEngine;
//射手1
public class Shooter1
{
private Notifier notifier;
private string name;
public Shooter1 (Notifier Notifier ,string Name)
{
this.notifier= Notifier ;
this.name = Name;
}
public void shootTheRed()
{
Debug.Log(" I will shoot the red one!");
}
}
using UnityEngine;
//射手1
public class Shooter2
{
private Notifier notifier;
private string name;
public Shooter2 (Notifier Notifier ,string Name)
{
this.notifier= Notifier ;
this.name = Name;
}
public void shootTheGreen()
{
Debug.Log(" I will shoot the green one!");
}
}
不再依赖抽象观察者
interface Notifier
{
void Notify();
string State{ get; set; }
}
使用delegate关键字
public class NotifyRadio : INotifer
{
private string action;
public delegate void Update();
public Update update;
public string State
{
get { return action; }
set { action = value; }
}
public void Notify()
{
update();
}
}
多播委托
using UnityEngine;
public class OberveManager : MonoBehaviour
{
NotifyRadio notifyRadio = new NotifyRadio();
void Start()
{
Shootor1 one = new Shootor1(notifyRadio, "1");
Shootor2 two = new Shootor2(notifyRadio, "2");
notifyRadio.update += one.shootTheRed;
notifyRadio.update += two.shootTheGreen;
}
void Update()
{
if(Input.GetKeyDown(KeyCode.C))
{
notifyRadio.Notify();
}
}
}
1.表示层和数据逻辑层的分离,让耦合的双方都依赖于抽象,而不是依赖于具体。
2.满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码
1.耗时?
发送通知只需简单地遍历列表,调用一些虚方法。只要这些方法不是特别耗时,否则这点消耗可以忽略。
2.观察者模式是同步的,你需要小心地在观察者中混合线程和锁。如果观察者试图获得被观察者拥有的锁,游戏就进入死锁了。在多线程引擎中,你最好使用事件队列来做异步通信。
1.一个对象发生改变需要同时改变其它类
2.链式触发机制,疫情模拟(A传B,B传C)
1.大话设计模式
2.游戏设计模式
3.观察者模式