Java 设计模式之观察者模式(Observer)

一、观察者模式(Observer Pattern)

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

  • 主题(Subject)和观察者(Observer)松耦合
  • 主题唯一依赖的是一个实现Observer接口的对象列表
  • Subject 和 Observer 类图

Java 设计模式之观察者模式(Observer)_第1张图片

二、模式详解

用户需求:项目组刚收到了一份合约,负责建立A公司的下一代气象站,系统中有三个部分:

  • 气象站(获取数据的物理装置)
  • WeatherData对象(追踪来自气象站的数据,并更新布告板)
  • 布告板(显示目前天气状况给用户看)(多种类型:状况、统计、天气预报等等)

需求分析:

  • 新的测量数据输入时,measurementsChanged() 方法就会被调用,用户不在乎此方法是如何被调用的,只在乎它被调用了
  • 项目组需要实现三个使用天气数据的布告板,一旦WeatherData有新的测量,这些布告必须马上更新
  • 此系统必须可扩展,如果有新的类型的布告板,必须可扩展,同时这些布告板可随时删减
  • 针对具体实现编程,在WeatherData里面添加具体实现,这样的话如果添加或删除布告板就要修改WeatherData代码,这样就很麻烦了,而这些具体实现可以用接口实现,即针对接口编程。

类图设计:

Java 设计模式之观察者模式(Observer)_第2张图片

代码示例:

Subject接口

package ObserverPattern;

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}

WeatherData实现subject的ConcreteSubject具体类

package ObserverPattern;

import java.util.ArrayList;

public class WeatherData implements Subject {
    // 观察者列表
    private ArrayList observers;
    private float temperature;
    private float humidity;
    private float pressure;
    // 初始化列表
    public WeatherData() {
        observers = new ArrayList();
    }
    // 注册
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    // 删除
    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }
    // 同时列表所有成员,更新数据
    @Override
    public void notifyObservers() {
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = (Observer) observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }
    // 数据更新,此方法就会被用户调用
    public void measurementsChanged() {
        notifyObservers();
    }

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

    // other methods
}

Observer接口

package ObserverPattern;

public interface Observer {
    public void update(float temp, float humidity, float pressure);
}

DisplayElement接口 

package ObserverPattern;

public interface DisplayElement {
    public void display();
}

CurrentConditionDisplay实现Observer的具体类(具体布告板)

package ObserverPattern;

// 此布告板实现了Observer接口,
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;
    // 构造器需要 weatherData (主题) 作为注册用
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    // 把湿度和温度保存起来,然后用display
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and" + humidity + "% humidity");
    }
}

WeatherStation测试类

package ObserverPattern;

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

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

至此,我们的系统已经完成了,可以看出:如果有新增和删减,我们不再需要修改WeatherData代码,不需要修改其他代码

StatisticsDisplay实现Observer的具体类

package ObserverPattern;

public class StatisticsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    // 构造器需要 weatherData (主题) 作为注册用
    public StatisticsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    // 把湿度和温度保存起来,然后用display
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    @Override
    public void display() {
        System.out.println("Statistics Display: " + temperature + "F degrees and" + humidity + "% humidity");
    }
}

更新测试类WeatherStation

package ObserverPattern;

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

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
        System.out.println("--------------------分割线------------------");
        weatherData.removeObserver(statisticsDisplay);
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

小结

  • 设计原则:为交互对象之间的松耦合设计而努力
  • 观察者模式的代表是MVC
  • 有多个观察者时,不可以依赖特定的通知次序

你可能感兴趣的:(设计模式(Java))