我也设计模式——18.Observer

Observer模式的迷人处在于它实现了.NET事件机制,这使得它在OO设计中大放光彩。
定义:观察者模式定义了一种一对多的依赖关系,让多个观察者Observer对象同时监听某一个主题对象Subject。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。


逐个分析:
1.Subject是一个集合类,负责将所有的Observer注册到弱集合arr中,这个由Attach()方法完成——我们同时会提供Detach()方法
    Notify()方法,负责通知所有的Observer有更新
        public void Notify()
        {
            
foreach (object obj in arr)
            {
                ((Observer)obj).Update();
            }
        }

2.ConcreteSubject继承于Subject类。
    Subject类是比较稳定的;而ConcreteSubject则提供了一些额外的关于被观察对象的信息,比如说UML图中的SubjectString属性

3.Observer是一个接口,提供了Update()方法,负责更新自身,这个方法由Subject.Notify()调用

4.ConcreteObserver类,是一个具体的观察者,它保持了一个对ConcreteSubject对象的引用,这个引用使得Observer知道自己观察的具体Subject对象,从而更新时,可以根据Subject的SubjectString属性,对自身进行一些修改
    class ConcreteObserver : Observer
    
{
        
private ConcreteSubject subject;

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


        
override public void Update()
        
{
            Console.WriteLine(subject.SubjectState);
        }

    }

Client端的实现:

            ConcreteSubject s = new ConcreteSubject();

            
//确保每个Observer都知道Subject
            Observer o1 = new ConcreteObserver1(s);
            Observer o2 
= new ConcreteObserver2(s);
            Observer o3 
= new ConcreteObserver3(s);

            
//确保Subject集合中包括所有的Observer
            s.Attach(o1);
            s.Attach(o2);
            s.Attach(o3);

            s.Notify();


Observer模式的变种:如果Observer不需要知道自己观察的具体Subject对象,那么UML可以简化为:
    Subject类不用修改
    Observer类需要加一个方法,用于将自身添加到Subject集合中

    public abstract class Observer
    
{
        
public void Register(Subject subject)
        
{
            subject.Attach(
this);
        }


        
public abstract void Update() { }
    }

    于是ConcreteObserver就简化到只需要实现Update()方法了


一个现实中的例子:猫叫了,于是老鼠吓跑了,主人惊醒了。我们可以使用event实现,也可以直接使用Observer实现,二者的原理是相同的。

基于委托的Observer模式:解除Observer与Subject之间的耦合关系,从而Observer不必有同样的接口
    在实现上只需要更改Subject类,并增加一个delegate如下:

delegate void UpdateDelegate(); 

class Subject
{
  
public UpdateDelegate UpdateHandler;
  
  
public void Attach( UpdateDelegate ud )
  
{
    UpdateHandler 
+= ud;
  }


  
public void Detach( UpdateDelegate ud )
  
{
    UpdateHandler 
-= ud;
  }

  
  
public void Notify()
  
{
    
if(UpdateHandler != null) UpdateHandler();
  }

}

于是Client端调用:

            ConcreteSubject s = new ConcreteSubject();

            
//o1需要知道s
            Observer o1 = new ConcreteObserver1(s);

            
//组链
            s.Attach(new UpdateDelegate(o1.Update));
            s.Attach(
new UpdateDelegate(ConcreteObserver2.Do));

            s.Notify();

观察者模式的效果有以下几个优点:

(1)观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。

(2)观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。

观察者模式有下面的一些缺点:

(1)如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

(2)如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。

(3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的——这时要加额外的同步锁。

(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。

 

posted @ 2007-10-04 11:41  包建强  Views(538)  Comments(0Edit  收藏  举报