《Headfirst设计模式》观察者模式-内置API

在这里插入图片描述
除了我们可以自己定义观察者之外,我们还可以使用java工具类中的API实现,但比起我们自己实现的接口,它会存在一些问题

java.util.Observable的黑暗面

如同你所发现的,可观察者是一个“类”而不是一个“接口”,更糟的是,它甚至没有实现一个接口。

  1. 首先,因为Observable是一个“类”,你必须设计一个类继承它。如果某类想同时具有Observable类和另一个超类的行为,就会陷入两难,毕竟Java不支持多重继承。 这限制了Observable的复用潜力。
  2. 因为没有Observable接口,所以你无法建立自己的实现,和Java内置的Observer API搭配使用,也无法将java.util的实现换成另一套做法的实现。
  3. 你会发现setChanged()方法被保护起来了(被定义成protected),这意味着:除非你继承自Observable,否则你无法创建Observable实例并组合到你自己的对象中来。这个设计违反了第二个设计原则:“多用组合,少用继承”。
 package Observable;

public interface DisplayElement {
    public void display();
}
package Observable;

import java.util.Observable;

/**
 * 我们不再需要追踪观察者了,也不需要管理注册与删除(让超类代劳即可)。所以我们把注册、添加、通知的相关代码删除。
 */
public class WeatherDate extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    //我们的构造器不再需要为了记住观察者们而建立数据结构了。
    public WeatherDate() {}

    //在调用notifuObservers()之前,要先调用setChanged()来指示状态已经改变
    public void measurementsChanged(){
        setChanged();
        //注意:我们没有调用notifyObservers()传送数据对象,这表示我们采用的做法是“拉”。
        notifyObservers();
    }

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

    //这些并不是新方法,只是因为我们要使用“拉”的做法,所以才提醒你有这些方法。察者会利用这些方法取得WeatherData对象的状态。
    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}
package Observable;


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

public class CurrentConditionsDisplay implements Observer, DisplayElement{
    private Observable observable;
    private float temperature;
    private float humidity;

    //现在构造器需要一Observable当参数,并将CurrentCondi- tionsDisplay对象登记成为观察者。
    public CurrentConditionsDisplay(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    //改变update()方法,增加Observable和数据对象作为参数。
    public void update(Observable obs, Object arg) {
        if (obs instanceof WeatherDate){
            WeatherDate weatherDate = (WeatherDate)obs;
            this.temperature = weatherDate.getTemperature();
            this.humidity = weatherDate.getHumidity();
            display();
        }
    }
    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature
                + "F degrees and " + humidity + "% humidity");
    }
}
package Observable;



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

public class ForecastDisplay implements Observer, DisplayElement {
    private float curPre =  29.92f;
    private float lastPre = 0;
    private Observable observable;

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

    @Override
    public void update(Observable obs, Object arg) {
        if (obs instanceof WeatherDate){
            WeatherDate weatherDate = (WeatherDate)obs;
            lastPre = curPre;
            curPre = weatherDate.getHumidity();
            display();
        }

    }
    @Override
    public void display() {
        System.out.print("Forecast: ");
        if (curPre > lastPre) {
            System.out.println("Improving weather on the way!");
        } else if (curPre == lastPre) {
            System.out.println("More of the same");
        } else if (curPre < lastPre) {
            System.out.println("Watch out for cooler, rainy weather");
        }
    }
}
package Observable;


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

public class HeatIndexDisplay implements Observer, DisplayElement {
    private float heatIndex = 0;
    private Observable observable;

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

    @Override
    public void update(Observable obs, Object arg) {
        if (obs instanceof WeatherDate){
            WeatherDate weatherDate = (WeatherDate)obs;
            heatIndex = computeHeatIndex(weatherDate.getTemperature(), weatherDate.getHumidity());
            display();
        }

    }
    private float computeHeatIndex(float t, float rh) {
        float index = (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh)
                + (0.00941695 * (t * t)) + (0.00728898 * (rh * rh))
                + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
                (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *
                (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +
                (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +
                0.000000000843296 * (t * t * rh * rh * rh)) -
                (0.0000000000481975 * (t * t * t * rh * rh * rh)));
        return index;
    }
    @Override
    public void display() {
        System.out.println("Heat index is " + heatIndex);
    }
}
package Observable;


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

public class StatisticsDisplay implements Observer, DisplayElement{
    private float max = 0.0f;
    private float min = 200;
    private float sum = 0.0f;
    private int num = 0;
    private Observable observable;

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

    @Override
    public void update(Observable obs, Object arg) {
        if (obs instanceof WeatherDate){
            WeatherDate weatherDate = (WeatherDate)obs;
            sum += weatherDate.getTemperature();
            num++;
            if (weatherDate.getTemperature() < min){
                min = weatherDate.getTemperature();
            }
            if (weatherDate.getTemperature() > max){
                max = weatherDate.getTemperature();
            }
            display();
        }
    }
    @Override
    public void display() {
        System.out.println("Avg/Max/Min temperature = " + (sum / num)
                + "/" + max + "/" + min);
    }
}

测试

package Observable;

public class WeatherStation {
    public static void main(String[] args) {
        WeatherDate weatherDate = new WeatherDate();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherDate);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherDate);
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherDate);
        HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherDate);

        weatherDate.setMeasurements(80, 65, 30.4f);
        weatherDate.setMeasurements(82, 70, 29.2f);
        weatherDate.setMeasurements(10, 10, 29.2f);
    }
}

在这里插入图片描述

总结

  • 观察者模式定义了对象之间一 对多的关系。
  • 主题(也就是可观察者)用一个共同的接口来更新观察者
  • 观察者和可观察者之间用松耦合方式结合(loosecoupling),可观察者不知道观察者的细节,只知道观察者实现 了观察者接口
  • 使用此模式时,你可从被观察者处推(push)或拉(pull) 数据(然而,推的方式被认为 更“正确”)。
  • 有多个观察者时,不可以依赖 特定的通知次序。
  • Java有多种观察者模式的实 现,包括了通用的java.util. Observable。
  • 要注意java.util.Observable实 现上所带来的一些问题。
  • 如果有必要的话,可以实现自己的Observable,这并不难, 不要害怕。
  • Swing大量使用观察者模式, 许多GUI框架也是如此。
  • 此模式也被应用在许多地方, 例如:JavaBeans、RMI。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值