定义

  1. 又叫 发布-订阅 模式
  2. 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
  3. 这个主题对象的状态发生变化时,会通知所有的观察者对象,使它们自己能够更新自己
  4. 观察者所做的工作就是在解除耦合,让耦合的双方都依赖于抽象,而不依赖于具体,从而使得各自变化不会影响到另一边

使用场景

  1. 关联行为场景,当一个对象发生改变时,需要同时改变其他对象
  2. 事件多级触发场景
  3. 跨系统的消息变换场景

举例

  1. 手机丢了,委托别人发消息
  2. 通知老板来了
  3. 拍卖,拍卖师观察最高价,并同时通知其他竞价者竞价
  4. 在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
  5. 猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者

代码实现

//抽象主题类 通知类
abstract class Subject
{
     private IList<ObServer> observers = new List<Observer>();
     

     private void Attach(Observer observer)
     {
           observers.Add(observer);
     }
    
     public void Detach(Observer observer)
     {
          observers.Remove(observer);
     }
    
     public void Notify()
     {
           foreach(var item in observers)
           {
                 item.Update();
           }
     }

}

//抽象的观察者类
abstract class Observer
{
     public abstract void Update();
}

//具体通知类
class ConcreteSubject: Subject
{
     public string SubjectState{ get; set; }
}

//具体观察者类
class ConcreteObserver: Observer
{
     private string name;
     private string observerState;
     private ConcreteSubject subject;

     public ConcreteObserver(ConcreteSubject subject, string name)
     {
          this.subject = subject;
          this.name = name;
     }
     
     public override void Update()
     {
           observerState = subject.SubjectState;
           Console.WriteLine("观察者{0}的新状态是{1}", name, observerState);
      }     
    
     public ConcreteSubject Subject { get { return subject; } set { subject = value; } }

}



void Main()
{
     ConcreteSubject s = new ConcreteSubject();
     s.Attach(new ConcreteObserver(s,"A"));
     s.Attach(new ConcreteObserver(s,"B"));
     s.Attach(new ConcreteObserver(s,"C"));
     

     s.SubjectState = "MS";
     s.Notify();

}

优点

  1. 观察者和被观察者是抽象耦合的
  2. 建立了一套触发机制

缺点

  1. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有观察者通知会花费很多时间
  2. 如果观察者和观察目标间有循环依赖,将会导致崩溃
  3. 没有相应的机制让观察者知道观察的目标是如何变化的