1. 为什么使用观察者模式
当存在一对多关系,存在多个观测者需要监听发布者发布的任务的时候,这个时候就需要使用观察者模式了。
在观察者模式中,观察者是单向依赖的,只有观察者依赖于目标,而目标是不会依赖于观察者的。
他们之间联系的主动权掌握在目标手中,只有目标知道什么时候需要通知观察者,整个过程中,观察者始终是被动的。
优点:
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
缺点:
依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
举例说明:比如现在存在一类玩家,当玩家暂停的时候需要调用其他方法,如A类需要停止自己的活动,B类也需要停止自己的活动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Main
{
public void Init()
{
Player player = new Player();
TestA testA = new TestA();
TestB testB = new TestB();
}
}
public class Player
{
/// <summary>
/// 发布者,停止所有活动
/// </summary>
public void Pause()
{
Debug.Log("游戏暂停");
}
}
public class TestA
{
/// <summary>
/// 订阅者,监听停止活动
/// </summary>
public void APauseFunction()
{
Debug.Log("A:游戏暂停");
}
}
public class TestB
{
/// <summary>
/// 订阅者,监听停止活动
/// </summary>
public void BPauseFunction()
{
Debug.Log("B:游戏暂停");
}
}
现在我们获得了我们的对象,但是他们现在之间还并没有关联,也无法调用,现在给他们添加调用的方法,并实现两个基类
public interface Observer
{
void Updata();
}
public abstract class Subject
{
public List<Observer> observers = new List<Observer>();
public void Attach(Observer observer)
{
observers.Add(observer);
}
public void Detach(Observer observer)
{
observers.Remove(observer);
}
public void Notify()
{
if (observers.Count > 0)
{
foreach (Observer item in observers)
{
item.Updata();
}
}
}
}
修改一开始的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Main : MonoBehaviour
{
private void Start()
{
Init();
}
public void Init()
{
Player player = new Player();
TestA testA = new TestA();
TestB testB = new TestB();
player.Attach(testA);
player.Attach(testB);
player.Notify();
}
}
public class Player : Subject
{
}
public class TestA : Observer
{
/// <summary>
/// 订阅者,监听停止活动
/// </summary>
private void APauseFunction()
{
Debug.Log("A:游戏暂停");
}
public void Updata()
{
APauseFunction();
}
}
public class TestB : Observer
{
/// <summary>
/// 订阅者,监听停止活动
/// </summary>
private void BPauseFunction()
{
Debug.Log("B:游戏暂停");
}
public void Updata()
{
BPauseFunction();
}
}
在场景中运行
现在我们实现了一个简单的观察者模式了
引入委托:
但是我们这么写相对来说十分麻烦,因为unity内部已经有现成的封装好的方法了,我们接下来可以引入委托,unity已经封装好了类Action和Func。
什么是委托:
委托是一种类,他是一种引用类型的数据类型,Action 可以为所有没有返回值类型的函数提供委托,通过范型参数对委托的输入参数类型进行限制。 而 Func 委托则将返回值类型也使用泛型参数确定
接下来我们简化一下代码
public abstract class Subject
{
public event System.Action observers;
public void Notify()
{
observers?.Invoke();
}
}
public class Main : MonoBehaviour
{
private void Start()
{
Init();
}
public void Init()
{
Player player = new Player();
TestA testA = new TestA();
TestB testB = new TestB();
player.observers += testA.APauseFunction;
player.observers += testB.BPauseFunction;
player.Notify();
}
}
public class Player : Subject
{
}
public class TestA
{
/// <summary>
/// 订阅者,监听停止活动
/// </summary>
public void APauseFunction()
{
Debug.Log("A:游戏暂停");
}
}
public class TestB
{
/// <summary>
/// 订阅者,监听停止活动
/// </summary>
public void BPauseFunction()
{
Debug.Log("B:游戏暂停");
}
}
运行结果如下:
成功运行,代码也更加简洁了