Java观察者模式 Observable Observer [U01]

来源:互联网 发布:js 垃圾回收机制 编辑:程序博客网 时间:2024/05/20 01:36

part1

JDK1.2后,Java提供了对观察者模式的支持接口和实现类。
其中接口java.util.Observer用来指定观察者,观察者必须实现 void update(Observable o, Object arg) 方法。
而java.util.Observable 用来指定观察物(被观察者、可被观察的),并且提供了一系列的方法。
读者可以很轻易的使用这个接口和实现类来实现观察者模式。

part2

java.util.Observer 只有一个简单的方法 void update(Observable o, Object arg)
其中,参数 Observable o 用于指定触发 update 方法的对象,Object arg 用于指定触发 update 方法时候的附加参数。
如果有桌面应用开发的读者应该很了解,这跟事件处理机制是完全一样的,其中 Observable o 可被看作事件源。
Object arg 可被看作消息。

part3

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

package t2;import java.util.Observable;/** * 报社(发布新闻)(发布者) * 继承 * 可观察(被观察)类 * @author Zet * */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 t2;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Observable;import java.util.Observer;/** * 读者 实现 观察者模式 *  * @author Zet * */public class Reader implements Observer {    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");    private String name;    public Reader(String name) {        super();        this.name = name;    }    /**     * 更新     */    @Override    public void update(Observable o, Object arg) {        if (o instanceof Publisher) {            Publisher p = (Publisher) o;            System.out.println("名称为" + this.name + " 看报者 于 " + sdf.format(new Date()) + " 订阅 " + p.getMagazineName());        }    }}
package t2;import org.junit.Test;public class TestCase {    @Test    public void register() {        Reader reader1 = new Reader("a reader");        Publisher publisher = new Publisher();        publisher.addObserver(reader1);        publisher.publish("java技术");    }}

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

part4

public void notifyObservers(Object arg)
传入的this,指的是参数

  • publisher.publish(“xxx”) // 发布事件 [发布报纸]

    • setChanged() // changed = true [新报纸出炉]
    • notifyObservers( (arg): this) // 通知[所有的]观察者 [准备送出报纸]
  • notifyObservers(this) //

    • ((Observer)arrLocal[i]).update(this, (arg):arg) // for循环 [送出报纸到每一个订阅者手中]

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

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

package t2;import java.util.Observable;/** * 电视台(发布新闻)(发布者) * 继承 * 可观察(被观察)类 * @author Zet * */public class TVStation extends Observable {    private String programmeName;    public String getProgrammeName() {        return programmeName;    }    public void play(String programmeName) {        this.programmeName = programmeName;        setChanged();        notifyObservers(this);    }}

然后修改 Reader 和 TestCast:

package t2;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Observable;import java.util.Observer;/** * 读者 实现 观察者模式 * * @author Zet */public class Reader implements Observer {    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");    private String name;    public Reader(String name) {        super();        this.name = name;    }    /**     * 更新     */    @Override    public void update(Observable o, Object arg) {        if (o instanceof Publisher) {            Publisher p = (Publisher) o;            System.out.println("名称为" + this.name + " 看报者 于 " + sdf.format(new Date()) + " 订阅 " + p.getMagazineName());        }        if (o instanceof TVStation) {            TVStation t = (TVStation) o;            System.out.println("名称为" + this.name + " 收看者 于 " + sdf.format(new Date()) + " 收看 " + t.getProgrammeName());        }    }}
package t2;import org.junit.Test;public class TestCase {    @Test    public void register() {        Reader reader1 = new Reader("a reader");        Publisher publisher = new Publisher();        publisher.addObserver(reader1);        TVStation tvStation = new TVStation();        tvStation.addObserver(reader1);        publisher.publish("java技术");        tvStation.play("java代码实战");    }}

最后我们可以看到,同一个观察者其实是可以注册到不同的(可观察)被观察者上面的,而传过来的 Observable o 其实可以用来检验到底是谁发过来的消息。
除此之外,我们还可以在接收到消息之后,进行撤销观察的工作。

package t2;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Observable;import java.util.Observer;/** * 读者 实现 观察者模式 * * @author Zet */public class Reader implements Observer {    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");    private String name;    public Reader(String name) {        super();        this.name = name;    }    /**     * 更新     */    @Override    public void update(Observable o, Object arg) {        if (o instanceof Publisher) {            Publisher p = (Publisher) o;            p.deleteObserver(this);            System.out.println("名称为" + this.name + " 看报者 于 " + sdf.format(new Date()) + " 订阅 " + p.getMagazineName());        }        if (o instanceof TVStation) {            TVStation t = (TVStation) o;//            t.deleteObserver(this);            System.out.println("名称为" + this.name + " 收看者 于 " + sdf.format(new Date()) + " 收看 " + t.getProgrammeName());        }    }}

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


开发工具
intellj idea

代码
https://github.com/dzetjava/javaDesignPattern/tree/master/learn_observer


来源:http://kentkwan.iteye.com/blog/739516


end

原创粉丝点击