设计模式之观察者模式

结构

观察者模式

说明

Define a one-to-many dependency between objects where a state change in one object results with all its dependents being notified and updated automatically.

在对象间定义一个一对多的联系性,由此当一个对象改变了状态,所有其他相关的对象会被通知并且自动刷新。

适用条件

  • 当抽象个体有两个相互依赖的层面时。 封装这些层面在单独物件内将可允许程序设计师单独地去变更与重复使用这些物件, 而不会产生两者之间的交互问题;
  • 当其中一个物件的变更会影响其他物件, 却又不知道多少无间必须被同时更新;
  • 当物件应该有能力通知其它物件, 又不应知道其他物件的实现细节时。

实现

public interface ISubject {

   void Attach(IObserver observer);

   void Detach(IObserver observer);

   void Notify();
}

public interface IObserver {

   void Update();

}

public class ConcreteSubject : ISubject {

   private readonly IList<IObserver> _observers = new List<IObserver>();

   public string State {
      get;
      set;
   }

   public void Attach(IObserver observer) {
      if (!this._observers.Contains(observer)) {
         this._observers.Add(observer);
      }
   }

   public void Detach(IObserver observer) {
      if (this._observers.Contains(observer)) {
         this._observers.Remove(observer);
      }
   }

   public void Notify() {
      foreach (var observer in _observers) {
         observer.Update();
      }
   }
}

public class ConcreteObserver : IObserver {
   
   private readonly ConcreteSubject _subject;

   public ConcreteObserver(ConcreteSubject subject) {
      this._subject = subject;
   }

   public void Update() {
      Console.WriteLine("Observer: subject state updated to {0} .", this._subject.State);
   }
}

class Client {

   static void Main(string[] args) {
      var subject = new ConcreteSubject();

      subject.Attach(new ConcreteObserver(subject));
      subject.Attach(new ConcreteObserver(subject));

      subject.State = "State1";
      subject.Notify();

      subject.State = "State2";
      subject.Notify();

      Console.ReadKey();
   }
}

.Net 4.0 内置了 IObservable 与 IObserver 接口用于实现观察者模式, 这两个接口的定义如下:

public interface IObservable<out T> {

   IDisable Subscribe(IObserver<T> observer);

}

public interface IObserver<in T> {

   void Next(T value);

   void OnError(Exception ex);

   void OnCompleted();
}