前置文章: 设计模式的原则
其他设计模式:用心理解设计模式
设计模式相关代码已统一放至 我的 Github
一、定义
行为型模式之一。
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
(定义对象间一对多的依赖关系,使得每当一个对象改变状态时,所有依赖于它的对象都会被通知并且自动更新。)
二、结构解析
观察者模式的一般结构有四种角色: 抽象主题、抽象观察者、具体主题、具体观察者。
抽象主题(Subject):持有/关联一组观察者,实现添加、移除观察者的方法,并定义一个在数据变化时通知观察者的接口。
抽象观察者(Observer):定义一个收到通知时刷新自身的接口。
具体主题(ConcreteSubject):继承抽象主题,维护一组原有数据,实现通知观察者的接口(可能主动,可能被动)。
具体观察者(ConcreteObserver):实现收到通知时刷新自身的接口。
三、评价
观察者模式是一个用于“同步数据/状态”、“通知变化” 的设计模式。
优点:通知交互依赖于抽象接口,一对多时系统结构仍然清晰。
四、发布订阅模式
发布订阅模式与观察者模式是有差别的。
发布订阅模式相比观察者模式新增了一个调度中心,用于集中处理主题与观察者的通知关系(类似中介者,将网状结构捋直为线性结构,如下图)。
主题不再关心观察者是谁,观察者也不关心触发事件的谁,两者都只与调度中心交互,从而使两者解耦。
发布订阅模式的实现将在之后写Unity框架的时候给出。
五、实现
观察者模式的实现
using System.Collections.Generic;
using UnityEngine;
namespace Observer
{
//抽象主题
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 abstract void Notify();
}
//抽象观察者
public abstract class Observer
{
public abstract void Update(string newData);
}
//具体主题
public class ConcreteSubject : Subject
{
private string data;
public ConcreteSubject(string initData)
{
this.data = initData;
}
//主动通知
public override void Notify()
{
foreach (Observer o in observers)
{
o.Update(data);
}
}
//改变数据并通知(被动通知)
public void ChangeData(string newData)
{
if (newData != data)
{
data = newData;
Notify();
}
}
}
//具体观察者X
public class ConcreteObserverX : Observer
{
public override void Update(string newData)
{
Debug.Log("ConcreteObserverX 观察到数据更新:" + newData);
}
}
//具体观察者Y
public class ConcreteObserverY : Observer
{
public override void Update(string newData)
{
Debug.Log("ConcreteObserverY 观察到数据更新:" + newData);
}
}
//具体观察者Z
public class ConcreteObserverZ : Observer
{
public override void Update(string newData)
{
Debug.Log("ConcreteObserverZ 观察到数据更新:" + newData);
}
}
public class Client
{
static public void Main()
{
ConcreteSubject subject = new ConcreteSubject("A");
subject.Attach(new ConcreteObserverX());
subject.Attach(new ConcreteObserverY());
subject.Attach(new ConcreteObserverZ());
//改变状态
subject.ChangeData("B");
}
}
}