设计模式:观察者

2020-12-16  本文已影响0人  山不转人自转

何为观察者模式:当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

介绍:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例: 拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价 拍卖师是观察者 而竞拍的人就是被观察者 被观察者的报价一变动 就需要观察者通知其他被被观察者。

优点:1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点:
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

实例:

观察者模式使用三个类 SubjectObserverClientSubject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类Observer 抽象类和扩展了抽象类 Observer 的实体类。
ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式

\color{#fbbc05}{主题接口}

/**
* 主题(发布者、被观察者)
*/
public interface Subject {

    /**
     * 注册观察者
     */
    void registerObserver(Observer observer);

    /**
     * 移除观察者
     */
    void removeObserver(Observer observer);

    /**
     * 通知观察者
     */
    void notifyObservers(); 
}

\color{#fbbc05}{观察者接口}

/**
 * 观察者
 */
public interface Observer {
    void update();
}

\color{#fbbc05}{公告牌用于显示的公共接口}

public interface DisplayElement {
    void display();
}

\color{#fbbc05}{WeatherData.java 实现}

public class WeatherData implements Subject {

    private List<Observer> observers;

    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压
    private List<Float> forecastTemperatures;//未来几天的温度

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

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

    @Override
    public void removeObserver(Observer observer) {
        this.observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, 
    float pressure, List<Float> forecastTemperatures) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        this.forecastTemperatures = forecastTemperatures;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

    public List<Float> getForecastTemperatures() {
        return forecastTemperatures;
    }
}

\color{#fbbc05}{显示当前天气的公告牌}

public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private WeatherData weatherData;

    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    public CurrentConditionsDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        this.weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("当前温度为:" + this.temperature + "℃");
        System.out.println("当前湿度为:" + this.humidity);
        System.out.println("当前气压为:" + this.pressure);
    }

    @Override
    public void update() {
        this.temperature = this.weatherData.getTemperature();
        this.humidity = this.weatherData.getHumidity();
        this.pressure = this.weatherData.getPressure();
        display();
    }
}

\color{#fbbc05}{显示未来几天天气的公告牌}

public class ForecastDisplay implements Observer, DisplayElement {

    private WeatherData weatherData;

    private List<Float> forecastTemperatures;//未来几天的温度

    public ForecastDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        this.weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("未来几天的气温");
        int count = forecastTemperatures.size();
        for (int i = 0; i < count; i++) {
            System.out.println("第" + i + "天:" + forecastTemperatures.get(i) + "℃");
        }
    }

    @Override
    public void update() {
        this.forecastTemperatures = this.weatherData.getForecastTemperatures();
        display();
    }
}

现在,整个气象局的\color{red}{WeatherData}应用就改造完成了。两个公告牌\color{red}{CurrentConditionsDisplay}\color{red}{ForecastDisplay}实现了\color{red}{Observer}\color{red}{DisplayElement}接口,在他们的构造方法中会调用\color{red}{WeatherData}\color{red}{registerObserver}方法将自己注册成观察者,这样被观察者\color{red}{WeatherData}就会持有观察者的应用,并将它们保存到一个集合中。当被观察者``WeatherData状态发送变化时就会遍历这个集合,循环调用观察者公告牌更新数据的方法。后面如果我们需要增加或者删除公告牌就只需要新增或者删除实现了\color{red}{Observer}\color{red}{DisplayElement}接口的公告牌就好了。

观察者模式将观察者和主题(被观察者)彻底解耦,主题只知道观察者实现了某一接口(也就是Observer接口)。并不需要观察者的具体类是谁、做了些什么或者其他任何细节。任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现了\color{red}{Observer}接口的对象列表。

\color{blue}{接下来上测试代码}

public class ObserverPatternTest {

    public static void main(String[] args) {

        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);

        List<Float> forecastTemperatures = new ArrayList<Float>();
        forecastTemperatures.add(22f);
        forecastTemperatures.add(-1f);
        forecastTemperatures.add(9f);
        forecastTemperatures.add(23f);
        forecastTemperatures.add(27f);
        forecastTemperatures.add(30f);
        forecastTemperatures.add(10f);
        weatherData.setMeasurements(22f, 0.8f, 1.2f, forecastTemperatures);
    }
}

\color{red}{输出结果:}

当前温度为:22.0℃
当前湿度为:0.8
当前气压为:1.2
未来几天的气温
第0天:22.0℃
第1天:-1.0℃
第2天:9.0℃
第3天:23.0℃
第4天:27.0℃
第5天:30.0℃
第6天:10.0℃

转载于:https://www.jianshu.com/p/d55ee6e83d66

上一篇下一篇

猜你喜欢

热点阅读