观察者模式

来源:互联网 发布:linux装tensorflow 编辑:程序博客网 时间:2024/05/19 20:47

1 观察者模式的定义

观察者模式,顾名思意就是观察与被观察的关系,比如你在烧开水得时时看着它开没开,你就是观察者,开水就是被观察者;再比如说你在带小孩,你关注她是不是饿了,是不是喝了,是不是撒尿了,你就是观察者,小孩就被观察者。观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。当你看这些模式的时候,不要觉得陌生,它们就是观察者模式。

观察者模式一般是一种一对多的关系,可以有任意个(一个或多个)观察者对象同时监听某一个对象。监听的对象叫观察者(后面提到监听者,其实就指观察者,两者是等价的),被监听的对象叫被观察者(Observable,也叫主题Subject)。被观察者对象在状态上发生变化时,会通知所有观察者对象,使它们能够做出相应的变化(如自动更新自己的信息)。
我们就以上面提到的烧开水的一个简单生活实例来模拟一下观察者模式。

代码ObserverModule.java:

//人,观察者class Person {    public void update(String data) {        System.out.println(data + 关电源...);    }}//水,被观察者class Water {    private Person person;    private boolean isBoiled;    public Water() {        isBoiled = false;    }    public void SetBoiled() {        isBoiled = true;        notifyObserve();    }    public void addObserver(Person person) {        this.person = person;    }    public void removeObserver() {        if (person != null) {            person = null;        }    }    public void notifyObserve() {        if (isBoiled && person != null) {            person.update(水开了,);            isBoiled = false;        }    }}//客户端public class ObserverModule {    public static void main(String args[]) {        Person person = new Person();        Water water = new Water();        water.addObserver(person);        water.SetBoiled();    }}

结果如下:
水开了,关电源…

这个代码非常简单,水开了就会通知人,人就去关电源。但也有一个问题,就是拓展性不好,不灵活。如果我们烧的开水不是用来喝,而用来洗澡,我就要监测它的温度,可能50度就关电源,也可能要60度才行,这样一个监听就不够了,还监听温度的随时变化;再比如水开了之后,我不是关电源,而是让它保温。你的updae又得改了……

版本2:ObserverModule.java

//观察者interface Observer {    public void update(Observable observable);}//被观察者abstract class  Observable {    protected boolean isChanaged;    protected List observers = new ArrayList();    public Observable() {        isChanaged = false;    }    public void addObserver(Observer observer) {        observers.add(observer);    }    public void removeObserver(Observer observer) {        observers.remove(observer);    }    public void removeObservers() {        observers.clear();    }    public void notifyObservers() {        if (isChanaged) {            for (int i = 0; i < observers.size(); i ++) {                observers.get(i).update(this);            }            isChanaged = false;        }    }}//人,温度监测class TemperatureObserver implements Observer{    @Override    public void update(Observable observable) {        Water water = (Water)observable;        System.out.println(温度: + water.getTemperature() +      状态: + water.getStatus());        System.out.println(TemperatureObserver observing...);    }}class BoildObserver implements Observer {    String doSomthing;    BoildObserver(String doSomthing) {        this.doSomthing = doSomthing;    }    @Override    public void update(Observable observable) {        Water water = (Water)observable;        if (water.getTemperature() >= 100) {            System.out.println(状态: + water.getStatus());            System.out.println(BoildObserver: + doSomthing);        }    }}//水,被观察者class Water extends Observable{    private double temperature;    private String status;    public Water() {        super();        this.temperature = 0;        this.status = 冷水;    }    public Water(Observer observer) {        this();        observers.add(observer);    }    public double getTemperature() {        return temperature;    }    public String getStatus() {        return status;    }    public void change(double temperature) {        this.temperature = temperature;        if (temperature < 40) {            status = 冷水;        } else if (temperature >= 40 && temperature < 60) {            status = 温水;        }else if (temperature >= 60 && temperature < 100 ) {            status = 热水;        } else {            status = 开水;        }        this.isChanaged = true;        notifyObservers();    }}//客户端public class ObserverModule {    public static void main(String args[]) {        TemperatureObserver temperatureObserver = new TemperatureObserver();        BoildObserver boildObserver1 = new BoildObserver(关闭电源...);        BoildObserver boildObserver2 = new BoildObserver(继续保湿...);        Water water = new Water(temperatureObserver);        water.addObserver(boildObserver1);        water.addObserver(boildObserver2);        water.change(45);        water.change(80);        water.change(100);    }}

结果如下:

温度:45.0 状态:温水TemperatureObserver observing…温度:80.0 状态:热水TemperatureObserver observing…温度:100.0 状态:开水TemperatureObserver observing…状态:开水BoildObserver:关闭电源…状态:开水BoildObserver:继续保湿…

2 观察者模式设计

通过上面这个活生生的例子,我们总结一下观察者模式的设计。
观察者模式的类结构关系如下:
这里写图片描述

在设计观察者模式的程序时要注意以下几点:

  1. 要明确谁是观察者谁是被观察者,只要明白谁是关注对象,问题也就明白了。一般观察者与被观察者之间的是多对一的关系,一个被观察对象可以有多个监听对象(观察者)。如一个编辑框,有鼠标点击的监听者,也有键盘的监听者,还有内容改变的监听者。
  2. Observable在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
  3. 被观察者至少需要有三个方法:添加监听者、移除监听者、通知Observer的方法;观察者至少要有一个方法:更新方法,更新当前的内容,作出相应的处理。
    : 添加监听者、移除监听者在不同的模型中可能会有不同命名,如观察者模型中一般,addObserver、removeObserver;在源-监听器(Source/Listener)模型中一般是attach/detach,应用在桌面编程的窗口中,还可能是attachWindow/detachWindow,或Register/UnRegister。不要被名称迷糊了,不管他们是什么名称,其实功能都是一样的,就是添加/删除观察者。
  4. 观察者模式的应用场景: <1>.对一个对象状态的更新需要其他对象同步更新;,或者一个对象的更新需要依赖另一个对象的更新;<2>.对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送。

推模型和拉模型

观察者模式根据其侧重的功能还可以分为推模型和拉模式

推模型:
被观察者对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。一般这种模型的实现中,会把被观察者对象中的全部或部分信息通过update的参数传递给观察者[update(Object obj) ]。
拉模型:
被观察者在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到被观察者对象中获取,相当于是观察者从被观察者对象中拉数据。一般这种模型的实现中,会把被观察者对象自身通过update方法传递给观察者[update(Observable observable ) ],这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。

JDK对观察者模式的支持

其实JDK已经提供了对观察者模式接口的定义了。在java.util库里面,提供了一个Observable类以及一个Observer接口,构成JAVA语言对观察者模式的支持。我们可以看一下Java中的源码:

//Observable接口:package java.util;public class Observable {    private boolean changed = false;    private Vector obs;    public Observable() {        obs = new Vector();    }    public synchronized void addObserver(Observer o) {        if (o == null)            throw new NullPointerException();    if (!obs.contains(o)) {        obs.addElement(o);    }    }    public synchronized void deleteObserver(Observer o) {        obs.removeElement(o);    }    public void notifyObservers() {        notifyObservers(null);    }    public void notifyObservers(Object arg) {        Object[] arrLocal;        synchronized (this) {        if (!changed)                return;            arrLocal = obs.toArray();            clearChanged();        }        for (int i = arrLocal.length-1; i>=0; i--)            ((Observer)arrLocal[i]).update(this, arg);    }    public synchronized void deleteObservers() {        obs.removeAllElements();    }    protected synchronized void setChanged() {        changed = true;    }    protected synchronized void clearChanged() {        changed = false;    }    public synchronized boolean hasChanged() {        return changed;    }    public synchronized int countObservers() {        return obs.size();    }}//Observer接口:package java.util;public interface Observer {    void update(Observable o, Object arg);}

通过前面的分析,再来看Java的源码,相信不会太难了。这里有个比较好的地方是Observable类中的addObserver、deleteObserver、notifyObservers等方法已经帮我们考虑了线程同步的问题,这样更安全。

3 参考

java:从消息机制谈到观察者模式

0 0
原创粉丝点击