旧游无处不堪寻
无寻处,惟有少年心
设计模式-观察者

观察者模式(Observer Pattern)是一种行为型设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个”观察”该对象的其他对象。

解释


拥有一些值得关注的状态的对象通常被称为目标,由于它要将自身的状态改变通知给其他对象,我们也将其称为发布者(publisher)。所有希望关注发布者状态变化的其他对象被称为订阅者(subscribers)。

观察者模式建议你为发布者类添加订阅机制,让每个对象都能订阅或取消订阅发布者事件流。该机制包括:

  1. 一个用于存储订阅者对象引用的列表成员变量
  2. 几个用于添加或删除该列表中订阅者的公有方法

无论何时发生了重要的发布者事件,它都要遍历订阅者并调用其对象的特定通知方法。

观察者模式 UML


适用场景


  1. 当一个对象状态的改变需要改变其他对象,或实际对象是事先未知的或动态变化的时,可使用观察者模式
  2. 当应用中的一些对象必须观察其他对象时,可使用该模式。但仅能在有限时间内或特定情况下使用

代码示例


using System;
namespace ObserverPatternDemo
{
public interface IObserver
{
// Receive update from subject
void Update(ISubject subject);
}

public interface ISubject
{
// Attach an observer to the subject.
void Attach(IObserver observer);

// Detach an observer from the subject.
void Detach(IObserver observer);

// Notify all observers about an event.
void Notify();
}

// The Subject owns some important state and notifies observers when the
// state changes.
public class Subject : ISubject
{
// For the sake of simplicity, the Subject's state, essential to all
// subscribers, is stored in this variable.
public int State { get; set; } = -0;

// List of subscribers. In real life, the list of subscribers can be
// stored more comprehensively (categorized by event type, etc.).
private List<IObserver> _observers = new List<IObserver>();

// The subscription management methods.
public void Attach(IObserver observer)
{
Console.WriteLine("Subject: Attached an observer.");
this._observers.Add(observer);
}

public void Detach(IObserver observer)
{
this._observers.Remove(observer);
Console.WriteLine("Subject: Detached an observer.");
}

// Trigger an update in each subscriber.
public void Notify()
{
Console.WriteLine("Subject: Notifying observers...");

foreach (var observer in _observers)
{
observer.Update(this);
}
}

// Usually, the subscription logic is only a fraction of what a Subject
// can really do. Subjects commonly hold some important business logic,
// that triggers a notification method whenever something important is
// about to happen (or after it).
public void SomeBusinessLogic()
{
Console.WriteLine("\nSubject: I'm doing something important.");
this.State = new Random().Next(0, 10);

Thread.Sleep(15);

Console.WriteLine("Subject: My state has just changed to: " + this.State);
this.Notify();
}
}

// Concrete Observers react to the updates issued by the Subject they had
// been attached to.
class ConcreteObserverA : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State < 3)
{
Console.WriteLine("ConcreteObserverA: Reacted to the event.");
}
}
}

class ConcreteObserverB : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State == 0 || (subject as Subject).State >= 2)
{
Console.WriteLine("ConcreteObserverB: Reacted to the event.");
}
}
}

class Program
{
static void Main(string[] args)
{
// The client code.
var subject = new Subject();
var observerA = new ConcreteObserverA();
subject.Attach(observerA);

var observerB = new ConcreteObserverB();
subject.Attach(observerB);

subject.SomeBusinessLogic();
subject.SomeBusinessLogic();

subject.Detach(observerB);

subject.SomeBusinessLogic();
// output

// Subject: Attached an observer.
// Subject: Attached an observer.

// Subject: I'm doing something important.
// Subject: My state has just changed to: 2
// Subject: Notifying observers...
// ConcreteObserverA: Reacted to the event.
// ConcreteObserverB: Reacted to the event.

// Subject: I'm doing something important.
// Subject: My state has just changed to: 1
// Subject: Notifying observers...
// ConcreteObserverA: Reacted to the event.
// Subject: Detached an observer.

// Subject: I'm doing something important.
// Subject: My state has just changed to: 5
// Subject: Notifying observers...
}
}
}