Observer模式

Observer模式

Observer模式在某个对象发生变化时,通知其相关对象。
具体请参看如图1所示的表示用户的G1、G2图。传感器得到通知后,该图的数据就会进行更新改写。
必须知道传感器对象是向哪个对象发出通知的。因此,表对象G1、G2事先已在传感器对象上完成注册。

于是将获得通知的图表对象称之为Observer。
那现在举个例子说明一下。看一下图2的闹钟系统。构成要素是闹钟和显示器。闹钟内发生变化时,闹钟就将该变化通知给显示器。

显示器分TextDisplay和DigitalDisplay这两种。
程序中闹钟对象内部的变化是由Notify()启动的,通知是通过Update()消息发送给显示器对象的。用对象图表示出来就如图3所示。

为了了解更加详细的动作,我们来画一下顺序图。

生成了被通知方-TextDisplay、DigitalDisplay对象之后,注册Alarm对象然后创建通知的关系。
这里Attach()消息也完成了注册。将其比作网络,就好比是发送一条subscribe邮件给要添加的通讯名单然后完成注册。因此,Alarm对象可以拥有应该通知的对象的名单。内部发生变化时,向通过Update()信息完成注册的各个对象发送信息。
此外,没必要有被通知对象时,就通过Detach()将其从名单中删除。这也好比是通过unsubscribe邮件从通讯名单中删除一样。那接下来看一下Observer模式的类图。

与变化相关的类事先创建好了通用的Subject类。这个子类将实现Alarm类。
和图5的类图一起也来看一下Java代码。在储存通知类的名单列表中,通过Vector型创建subscriber。在列表上注册用Attach()中的subscriber.addElement()ACE。处理排列等列表时,请回想一下之前介绍的Iterator模式。删除的时候在Detach()中变成了subscriber.removeElement()。 内部变化变成Notify()。

其中通过while(e.hasMoreElements()),使通知对象的列表进行循环,通过((Display) e.nextElement()).Update(this)发送通知消息。由于该Update()是列表中对象的方法,因此也成为TextDisplay和DigitalDisplay对象的方法。或许您已经注意到,运用多态性,通过对象就能将方法的实现进行替换。
接下来看一下被通知方的类。这也是要创建称为通用Display的超类。因此,创建了不同的 TextDisplay和DigitalDisplay两个子类。由于通知用的方法的Update()逻辑要进行不一样的实现,在子类中就写Update()编码。看一下TextDisplay类,生成类的时候,通过Attach(this)在用引数传递的Subject对象(实际上是Alarm的对象)上注册。因为是将自身的this作为引数,因此也能在自身上进行注册。关于Update(),因为是样本程序,TextDisplay和 DigitalDisplay类的区别仅仅在于简单的println()消息上。

    Observer例子的Java编码
    
            abstract class Display{
                void Update(Subject s){}
            }
            class TextDisplay extends Display{
                TextDisplay(Subject&s){
                    System.out.println("TextDisplay Attach");
                    s.Attach(this);
                }
                void Update(Subject s){
                System.out.println("TextDisplay Update");

                //在此输入TextDisplay的逻辑

                }
            }
            class DigitalDisplay extends Display{
                DigitalDisplay(Subject s){
                    System.out.println("DigitalDisplay Attach");
                    s.Attach(this);
                }
                void Update(Subject s){
                System.out.println("DigitalDisplay Update");

                //在此输入DigitalDisplay的逻辑

                }
            }
            class Subject extends Object{
                Vector subscriber;
                Subject(){
                    subscriber = new Vector();
                }
                void Attach(Display o){
                subscriber.addElement(o);
                }
                void Detach(Display o){
                    subscriber.removeElement(o);}void Notify(){
                    Enumeration e = subscriber.elements();
                    while(e.hasMoreElements()){
                        ((Display)e.nextElement()).Update(this);
                    }
                }
            }
            class Alarm extends Subject{
            }

            Observer例的主要部分

                Alarm al;
                al = new Alarm();

                DigitalDisplay d = new DigitalDisplay(al);
                TextDisplay t = new TextDisplay(al);

            发生变化时,al.Notify();