Java观察者模式Observable与Observer 的理解

    |     2015年5月3日   |   设计模式   |     0 条评论   |    1778

JDK 1.2 之后,Java 在 java.util 里提供了观察者模式的接口和实现类:观察者实现 Observer,被观察者继承 Observable。

观察者必须实现 void update(Observable o, Object arg)。读者可以很轻易地用这一对类型把推送关系搭起来。

一、Observer 与 Observable

update 的第一个参数是触发这次通知的对象,第二个是附加参数。做过桌面事件的会觉得眼熟:前者像事件源,后者像消息。

类型 角色 关键方法
Observer 观察者 update(Observable o, Object arg)
Observable 被观察者 addObserver / setChanged / notifyObservers / deleteObserver

二、读者订阅杂志

出版社出杂志时主动告知读者。先写被观察者 Publisher(通知前要 setChanged()):

package com.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);
    }
}

读者实现 Observer:

package com.observer.observer;

import java.util.Observable;
import java.util.Observer;
import com.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());
    }
}

原文第一段测试只调用了 publish,没有 addObserver,读者收不到消息。完整注册如下:

Publisher publisher = new Publisher();
Reader reader = new Reader();
publisher.addObserver(reader);
publisher.publish("极客之家");

这是一种主动推送:出版时通知已注册的读者。

三、为什么 notifyObservers(this)?

同一个观察者可以挂到不同被观察者上,传来的 Observable o 用来分辨消息是谁发的。再引入电视台:

package com.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;
    }
}
package com.observer.observer;

import java.util.Observable;
import java.util.Observer;
import com.observer.observable.Publisher;
import com.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.observer.test;

import org.junit.Test;
import com.observer.observable.Publisher;
import com.observer.observable.TVStation;
import com.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("极客之家");
        tvStation.play("色戒");
    }
}

四、收完消息可以取消订阅

在 update 里调用 deleteObserver(this) 即可撤销对出版社的观察:

@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());
    }
}

一句话总结:先 addObserver,再 setChanged + notifyObservers;传来的 Observable 用来分辨是谁在推,不看了就 deleteObserver。

转载请注明来源:Java观察者模式Observable与Observer 的理解
本文链接地址:https://ai.zhousir.top/?p=612
回复 取消