设计模式 - 观察者模式
观察者模式
含义:定义了对象之间的一对多依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且自动更新。又称为“发布-订阅模式”
实现过程:
- 理论性:创建一个主题对象及多个订阅者,主题对象和订阅者之间形成一对多关系,当主题发生变化时,调用通知事件函数,使其订阅者做出相应改变
- 比喻:居民订阅日报,报社每天将最新的报纸分发给订报者,订报者根据最新的报纸调整一天的形成,而没有订阅的人则无法享受该服务
优缺点:
- 优点:
- 建立了 “主题-->多订阅者” 的事件机制
- 使耦合双方依赖于抽象而不是具体(抽象耦合)
- 缺点:
- 订阅者越多,主题通知用时越长,费时
- 没有相应的机制让订阅者知道所订阅的对象是怎么发生变化的,仅仅知道变化了
- 如果订阅者和主题对象间有循环依赖,可能导致系统崩溃
适用场景:
- 一个对象的改变将导致其他一个或多个对象也发生改变
- 一个对象必须通知其他对象,而并不知道这些对象是谁
- 触发反应机制
项目示例:
主题对象(布加拉提),订阅者(普罗修特、贝西),当布加拉提出现时,普罗修特和贝西做出各自反应:
// 主题接口:
// --------
interface Subject
{
//添加/删除订阅者
void Attach(Observer observer);
void Detach(Observer observer);
//通知事件
void Notify();
}
// 具体主题:
// --------
class ConcreteSubject : Subject
{
// 订阅者清单
private List<Observer> observers = new List<Observer>();
public void Attach(Observer obs)
{
observers.Add(obs);
}
public void Detach(Observer obs)
{
if (observers.Contains(obs))
observers.Remove(obs);
}
public void Notify()
{
//主题改变则通知其所有订阅者进行变化
Console.WriteLine("出现了野生布加拉提!");
foreach (Observer o in observers)
o.Update();
}
}
// 抽象订阅者:
// ----------
abstract class Observer
{
protected string name;
public Observer(string name)
{
this.name = name;
}
// 各订阅者对通知事件的反应
public abstract void Update();
}
// 具体订阅者:
// ----------
class ConcreteObserverA : Observer
{
public ConcreteObserverA(string name) : base(name) { }
public override void Update()
{
Console.WriteLine($"{name} 发动替身: \"The Grateful Dead!\"");
}
}
class ConcreteObserverB : Observer
{
public ConcreteObserverB(string name) : base(name) { }
public override void Update()
{
Console.WriteLine($"{name} 发出呐喊:\"普罗修特大哥!\"");
}
}
// 客户端:
// ------
class Client
{
static void Main(string[] args)
{
//创建主题对象(布加拉提)
ConcreteSubject Bucciarati = new ConcreteSubject();
//创建订阅者(普罗修特、贝西)
ConcreteObserverA Prosciutto = new ConcreteObserverA("普罗修特");
ConcreteObserverB Pesci = new ConcreteObserverB("贝西");
//订阅者订阅主题对象
Bucciarati.Attach(Prosciutto);
Bucciarati.Attach(Pesci);
//主题对象通知事件(布加拉提出现)
Bucciarati.Notify();
/* OUT:
出现了野生布加拉提!
普罗修特 发动替身: "The Grateful Dead!"
贝西 发出呐喊:"普罗修特大哥!"
*/
}
}
备注:
除了上面的方法,C#中提供的 委托事件机制 也可较好实现观察者模式,该示例代码:观察者模式示例_委托版 - SouthBegonia's Github