观察者模式深度分析

概述

观察者模式是一种很常用的设计模式,Android中的广播(Broadcast)就是用观察者模式设计的,再往大一步,诸如微博这种社交平台也是用的观察者模式,观察者模式亦被称作发布-订阅模式。观察者模式包含两个要素:目标对象、观察者对象。其中,当目标对象的状态发生改变时,它所依赖的观察者将立即得到通知,通知携带的数据将在消息中心得到处理

内容

1、使用观察者模式的场景

当一个对象的状态需要被多个对象了解,以保证高度协作。

2、观察者模式的结构

3、观察者模式的实现

假设有一个气象监测模型,那么Observer是需要获取气象通知的观察者,Subject则是气象主题,作为被观察者。

3.1、主题接口

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

主题的三个核心功能即是:注册观察者、删除观察者、通知观察者。所以主题接口务必抽象这三个方法。

3.2、观察者接口

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

当气象状态变化时,主题会把相关状态值作为方法参数传送给观察者。

3.3、显示接口

这个和观察者模式无关。

public interface DisplayElement {
    public void display();
}

3.4、实现主题接口

public class WeatherData implements Subject {
    private ArrayList observers;

    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        this.observers = new ArrayList();
    }

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

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

    public void notifyObservers() {
        for (Observer o : observers) {
            o.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();
    }
}

除了实现Subject接口的三方法外,WeatherData中可以有自己特定的方法,用以实现具体的功能,如setMeasurements(),用以改变观察值。

在实际运用中,当气象状态信息真实变化,或状态需被按时发布时,这个方法将被调用。

3.5、实现观察者接口

public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private float temperature;
    private float humidity;

    public CurrentConditionsDisplay() {
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }

    @Override
    public void display() {
        Log.d("display", "Current conditions:" + temperature + "F degrees and" + humidity + "% humidity");
    }
}

这里的观察者类型是CurrentConditionsDisplay,实现了Observer接口的update()方法,和DisplayElement的display()方法。
从WeatherData类中可以看到,update()方法在WeatherData类型的对象的数据改变时被调用,作为观察者的CurrentConditionsDisplay类型对象将获得最新的数据,接着调用display()展示数据。但观察者能获取主题所发布的新数据的前提是,观察者绑定了主题,且未被主题删除。

public class Test {

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

        CurrentConditionsDisplay display = new CurrentConditionsDisplay();
        weatherData.registerObserver(display);
        weatherData.setMeasurements(80, 65, 30.4f);

        //weatherData.removeObserver(display);
    }
}

主通过registerObserver()方法,主题注册了观察者,这一步即是订阅
当主题调用setMeasurements()方法,就会通知观察者最新消息,这一步即是发布

4、java 内置的观察者接口

实现java.util.Observable接口,然后调用两个方法:
先调用setChanged(),标记状态已经改变;
然后调用notifyObservers()方法或notifyObservers(Object arg)方法,通知观察者,如果调用notifyObservers(Object arg)方法,其参数会被传送给观察者。

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 = pressure;
        this.pressure = pressure;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}

观察者实现:

public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private float temperature;
    private float humidity;

    public CurrentConditionsDisplay() {
    }

    @Override
    public void display() {
        Log.d("display", "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();
        }
    }
}

使用范例:

public class Test {

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

        CurrentConditionsDisplay display = new CurrentConditionsDisplay();
        weatherData.addObserver(display);
        weatherData.setMeasurements(80, 65, 30.4f);

        //weatherData.deleteObserver(display); //删除观察者
    }
}

不过是方法名变了。

你可能感兴趣的:(Java,编程内功-设计模式)