设计模式随笔-观察者模式

观察者模式

观察者模式是JDK中使用最多的模式之一,非常有用。它是一对多关系,以及松耦合。有了观察者,你将会消息灵通。

天气监测应用概况

现在有一个应用:气象监测系统。
此系统中有三个部分分别是:气象站(获得实际气象数据的装置)、WeatherData对象(追踪来自气象站的数据,并更新数据)和显示器(显示目前天气状况给用户看)。
如下图所示:
应用大纲

需求

现在我们接受这个项目,我们的工作就是建立一个应用,利用WeatherData对象获取气象站的实时数据,并更新到显示器上面:目前状况显示器、气象统计显示器和天气预报显示器。

新鲜出炉的WeatherData类

如图:
原始WeatherData类
measurementsChanged()方法能调用三个天气显示器实时更新数据。方法如下:

public void measurementsChanged(){
    float temp = getTemperature();
    float humidity = getHumidity();
    float pressure = getPressure();

    //分别调用三个显示器对象的update()方法更新天气显示器信息
    currentConditionsDisplay.update(temp, humidity, pressure);
    statisticsDisplay.update(temp, humidity, pressure);
    forecastDisplay.update(temp, humidity, pressure);
}

但是上面针对的实现编程,会导致我们以后再正价或者删除布告板是必须修改代码。改变的地方需要封装起来、针对接口编程而不针对实现编程。

认识观察者模式

就像报纸的订阅,出版商+订阅者=观察者模式。
出版者=“主题”,订阅者=“观察者”
详细分析如下图:
观察者模式模型

观察者模式定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

观察者模式UML图如下:
观察者模式UML

观察者模式样例代码

首先是主题(Subject)接口代码:

/**
 * 观察者模式里面的-主题
 * Created by zz on 2016/8/24.
 */
public interface Subject {
    /**
     * 注册订阅者
     * @param observer
     */
    public void registerObserver(Observer observer);

    /**
     * 取消订阅者
     * @param observer
     */
    public void removeObserver(Observer observer);

    /**
     * 当主题状态改变时,通知所有订阅者
     */
    public void notifyObject();
}

订阅者(Observer)接口代码:

/**
 * 订阅者
 * Created by zz on 2016/8/24.
 */
public interface Observer {
    public void update(float temp, float humidity, float pressure);
}

WeatherData类代码实现:

public class WeatherData implements Subject {
    private List<Observer> observers;    //订阅者
    private float temperature;    //温度
    private float humidity;    //湿度
    private float pressure;    //压强

    public WeatherData(){
        observers = new ArrayList<Observer>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        int i = observers.indexOf(observer);
        if (i > 0){
            observers.remove(i);
        }
    }

    @Override
    public void notifyObject() {
        for (int i=0; i<observers.size(); i++){
            Observer observer = observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }

    /**
     * 当主题改变时调用的方法
     */
    public void measurementsChange(){
        notifyObject();
    }

    public void setMeasurements(float temperature, float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChange();
    }
}

显示器(CurrentConditionsDisplay)类代码实现:

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;    //温度
    private float humidity;    //湿度
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject subject){
        this.weatherData = subject;
        weatherData.registerObserver(this);
    }
    @Override
    public void display() {
        System.out.println(temperature + ":" + humidity);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }
}
//改变的方法提取出来
public interface DisplayElement {
    public void display();
}

test方法测试:

public void test(){
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay =
                new CurrentConditionsDisplay(weatherData);    //订阅主题
        weatherData.setMeasurements(80, 65, 30.4F);
        weatherData.setMeasurements(75, 70, 29.2F);
        weatherData.setMeasurements(78, 90, 29.2F);
    }

上面的代码我只写了一个显示天气温度的显示器类,还有其他湿度显示器等也是同样原理,只是可能计算湿度的算法不一样而已,这里就不在累赘讲述了。

JAVA内置的观察者模式

在java.util包中内含了一个叫Observer接口与Observable类,这与我们自己手动创建的Subject接口与Observer接口很相似。只是java内置的Observable是一个抽象类,而我们都用了接口来实现。
下面是利用java内置的气象站OO设计:
内置java观察者模式

内置的java观察者模式是如何把对象变成观察者的呢?其实和自己设计的观察者模式一样,该内置的java方法调用了Observable对象的addObserver()方法。如果不想在当观察者的话就调用该对象的removeObserver()方法。
那观察者如何收到通知呢?通过先调用Observaable对象的setChanged()方法,然后调用notifyObservers()方法通知就可以调用所有在该对象注册的观察者对象了。为什么要先调用setChanged(),这是因为内置的java观察者有一个标志位boolean change,当把标志位修改成ture时,notify方法才会执行通知。
那接收者是如何接收到通知的呢?主要是通过Observer接口的update()方法了,同自己设计的一个样:

public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);
}

Object arg参数没有说明时可以传空。

利用内置的java观察者模式重做气象站

WeatherData代码:

import java.util.Observable;

/**
 * 内置java观察者
 * Created by zz on 2016/8/24.
 */
public class WeatherData extends Observable {
    private float temperature;    //温度
    private float humidity;    //湿度
    private float pressure;    //压强
    public WeatherData(){}

    public void measurementsChanged(){
        setChanged();
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}

某个显示器:

import java.util.Observable;
import java.util.Observer;

/**
 * Created by zz on 2016/8/25.
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private Observable observable;
    private float temperature;
    private float humidity;

    public CurrentConditionsDisplay(Observable observable){
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void display() {
    System.out.println("temperature:"+temperature + "humidity:"+ humidity);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData){
            WeatherData weatherData = (WeatherData) o;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            display();
        }
    }
}

大家可能注意到了Observable是一个类,而不是一个接口,而且它也没有实现一个接口,这样可能限制了它的使用和复用。这一点需要大家注意一下哦。
在jdk中还有挺多地方用到观察者模式的哦,比如:Swing和javaBeans中,他们都实现了观察者模式,有时间大家可以看看哟。

总结

在本章中,让我学到了一些知识:
1.为交互对象之间的松耦合设计而努力。
2.观察者模式-在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值