Java观察者模式 java.util.Observable 与 java.util.Observer 的理解及测试实例

来源:互联网 发布:鲸藤壶 知乎 编辑:程序博客网 时间:2024/05/16 04:44

声明:本文章是转载自

Kent.Kwan.的技术专栏

http://blog.csdn.net/kenthong/article/details/5725522。文章中的总结部分是对原博文的补充,是基于其他网友的讨论和自己的理解。若有不同观点,请留言指教。


Part I

JDK1.2后,Java提供了对观察者模式的支持接口和实现类。

其中接口 java.util.Observer 用来指定观察者,观察者必须实现 void update(Observable o, Object arg) 方法。

而 java.util.Observable 用来指定观察物(被观察者、可被观察的),并且提供了一系列的方法。读者可以很轻易的使用这个接口和实现类来实现观察者模式。

 

Part II

java.util.Observer 只有一个简单的方法 void update(Observable o, Object arg)

其中,参数 Observable o 用于指定触发 update 方法的对象, Object arg 用于指定触发 update 方法时候的附加参数。

如果有桌面应用开发的读者应该很了解,这跟事件处理机制是完全一样的,其中 Observable o 可被看作事件源。 Object arg 可被看作消息。

 

Part III

说了那么多,我们还是动手写个例子吧。这里我们以读者订阅杂志为例子。

package com.gzmu.observer.observable;import java.util.Observable;public class Publisher extends Observable {        private String magazineName;        public String getMagazineName() {        return magazineName;    }        public void publish(String magazineName) {        this.magazineName = magazineName;        setChanged();        notifyObservers(this);    }    }

package com.gzmu.observer.observer;import java.util.Observable;import java.util.Observer;import com.gzmu.observer.observable.Publisher;public class Reader implements Observer {    @Override    public void update(Observable o, Object arg) {        Publisher p = (Publisher) o;        System.out.println("我要订阅" + p.getMagazineName());    }}

package com.gzmu.observer.test;import org.junit.Test;import com.gzmu.observer.observable.Publisher;public class TestCase {    @Test    public void register() {        Publisher publisher = new Publisher();        publisher.publish("Kent.Kuan的技术空间");    }}

这里很清楚的看到,当出版社出版杂志的时候,会主动的告知读者,读者就会订阅杂志,这也是一种主动推送的模式。

 

Part IV

这里大家会发现,调用 notifyObservers() 的时候,为什么传进当前对象 this 呢?而这个 this, 我们在读者那也没用到啊。这个问题曾经也让我觉得很苦恼,之前我也不清楚为什么观察者要拿到被观察对象的引用,但是,我们看看下面这个例子。

首先我们引用一个新的类:

package com.gzmu.observer.observable;import java.util.Observable;public class TVStation extends Observable {    private String programmeName;    public void play(String programmeName) {        this.programmeName = programmeName;        setChanged();        notifyObservers(this);    }    public String getProgrammeName() {        return programmeName;    }}

然后修改Reader和TestCase:

package com.gzmu.observer.observer;import java.util.Observable;import java.util.Observer;import com.gzmu.observer.observable.Publisher;import com.gzmu.observer.observable.TVStation;public class Reader implements Observer {    @Override    public void update(Observable o, Object arg) {        if (o instanceof Publisher) {            Publisher p = (Publisher) o;            System.out.println("我要订阅" + p.getMagazineName());        }        if (o instanceof TVStation) {            TVStation t = (TVStation) o;            System.out.println("我要收看" + t.getProgrammeName());        }    }}

package com.gzmu.observer.test;import org.junit.Test;import com.gzmu.observer.observable.Publisher;import com.gzmu.observer.observable.TVStation;import com.gzmu.observer.observer.Reader;public class TestCase {        @Test    public void register() {                Reader reader = new Reader();                Publisher publisher = new Publisher();        publisher.addObserver(reader);                TVStation tvStation = new TVStation();        tvStation.addObserver(reader);                publisher.publish("Kent.Kwan的技术空间");        tvStation.play("色戒");            }    }

最后我们可以看到,同一个观察者其实是可以注册到不同的被观察者上面的,而传过来的 Oberverable o 其实可以用来检验到底是谁发过来的消息。

除此以外,我们还可以在接受到消息之后,进行撤销观察的工作。

package com.gzmu.observer.observer;import java.util.Observable;import java.util.Observer;import com.gzmu.observer.observable.Publisher;import com.gzmu.observer.observable.TVStation;public class Reader implements Observer {    @Override    public void update(Observable o, Object arg) {        if (o instanceof Publisher) {            Publisher p = (Publisher) o;            p.deleteObserver(this);            System.out.println("我要订阅" + p.getMagazineName());        }        if (o instanceof TVStation) {            TVStation t = (TVStation) o;            System.out.println("我要收看" + t.getProgrammeName());        }    }}

 通过 deleteObserver() 方法就可以撤销观察出版社对象。

自己的测试代码

主程序

package edu.wit.kelvin.demo;public class Main {public static void main(String[] args){// 创建一个观察者对象Reader r = new Reader() ;// 创建一个被观察者对象Publicher p = new Publicher() ;// 指定r为p的观察者,建立观察者和被观察者之间的关联p.addObserver(r) ;p.publich("War and Peace!") ;}}
观察者类

package edu.wit.kelvin.demo; import java.util.Observer;import java.util.Observable;import edu.wit.kelvin.demo.Publicher;public class Reader implements Observer{public void update(Observable o , Object args){Publicher p = (Publicher)o ;System.out.println("i will subscribe "+p.getMagazineName()) ;System.out.println("i will subscribe "+args) ;System.out.println("i will subscribe "+o) ;}}
被观察者类

package edu.wit.kelvin.demo;import java.util.Observable;public class Publicher extends Observable{private String magazineName ;public String getMagazineName(){return this.magazineName;}public void publich(String magazineName){this.magazineName = magazineName ;setChanged() ;this.notifyObservers(this) ;}}

运行结果

i will subscribe War and Peace!i will subscribe edu.wit.kelvin.demo.Publicher@1bab50ai will subscribe edu.wit.kelvin.demo.Publicher@1bab50a

由此可见当在被观察者类中,notifyObservers(this)时,update的第二个参数为被观察者this。与第一个参数一样。由此可以证明,notifyObservers(args)中的参数是传递给了update()的第二个参数的。


总结:

  1. 消息在被观察者和观察者之间的传递流程

  1. 被观察者调用setChanged()方法,相当于发出一个信号,告诉系统,自己的状态发生了改变,告诉系统区通知观察者。
  2. 被观察者,接着调用notifyObservers(args);通知观察者,args为要传递给观察者的参数,即观察者update()中的第二个参数(object args)
  3. 执行观察者的update()方法

   2. 注意

notifyObservers(args)中的args传递给了update(Observable o , Object args)的args,并不是如原博文中那样。


0 0