JAVA设计模式之观察者模式

120 阅读3分钟

本文介绍23种设计模式之观察者模式。

定义

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

描述

  • 模式名称:OBSERVER(观察者)
  • 类型:对象行为型模式
  • 意图:定义对象间的一种一对多的依赖关系 ,当一个对象的状态发生改变时 , 所有依赖于它的对象都得到通知并被自动更新。
  • 适用性:
    • 当对一个对象的改变需要同时改变其它对象 , 而不知道具体有多少对象有待改变。
    • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的。
  • 效果:
  • 优点:
    • 目标和观察者间的抽象耦合。
    • 支持广播通信。
  • 缺点:
    • 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
    • 如果目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。

结构

image.png

参与者

  • Subject(目标)
    • 目标知道它的观察者。可以有任意多个观察者观察同一个目标。
    • 提供注册和删除观察者对象的接口。
  • Observer(观察者)
    • 为那些在目标发生改变时需获得通知的对象定义一个更新接口。
  • ConcreteSubject(具体目标)
    • 将有关状态存入各ConcreteObserver对象。
    • 当它的状态发生改变时, 向它的各个观察者发出通知。
  • ConcreteObserver(具体观察者)
    • 维护一个指向ConcreteSubject对象的引用。
    • 存储有关状态,这些状态应与目标的状态保持一致。
    • 实现Observer的更新接口以使自身状态与目标的状态保持一致。

举一个例子

公司要和气象局合作,气象局提供温度,湿度,气压的数据,需要设计气象布告板,动态展示数据,并且可以自定义布告板和新增删除布告板的功能。

在此例子中,气象数据就是目标,气象布告板就是观察者

image.png

目标的父类

public interface Subject {

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObserver();
}

观察者父类

public interface Observer {


    void update(WeatherEvent weatherEvent);
}

布告板接口

public interface DisplayEle {

    void display();
}

事件对象,用于发送给观察者

public class WeatherEvent {

    private double temperature;

    private double humidity;

    private double pressure;


    public double getTemperature() {
        return temperature;
    }

    public void setTemperature(double temperature) {
        this.temperature = temperature;

    }

    public double getHumidity() {
        return humidity;
    }

    public void setHumidity(double humidity) {
        this.humidity = humidity;

    }

    public double getPressure() {
        return pressure;
    }

    public void setPressure(double pressure) {
        this.pressure = pressure;

    }


}

天气数据,具体目标

public class WeatherData implements Subject {

    private int state;

    private WeatherEvent weatherEvent;

    private ArrayList<Observer> list;//内部维护一个观察者集合


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

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }


    public WeatherEvent getWeatherEvent() {
        return weatherEvent;
    }

    public void setWeatherEvent(WeatherEvent weatherEvent) {
        this.weatherEvent = weatherEvent;
        notifyObserver();
    }


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

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

    @Override
    public void notifyObserver() {
        for (int i = 0; i < list.size(); i++) {
            Observer observer = list.get(i);
            observer.update(weatherEvent);
        }

    }
}

具体观察者

public class CurrentConditionsDisplay implements Observer,DisplayEle {

    private WeatherEvent weatherEvent;

    @Override
    public void display() {
        System.out.println(this.toString()+"===="+weatherEvent.getHumidity()+"==="+weatherEvent.getPressure()+"==="+weatherEvent.getTemperature());
    }


    @Override
    public void update(WeatherEvent weatherEvent) {
          this.weatherEvent = weatherEvent;
          display();
    }
}

jdk 也提供了相似的支持,具体的大家可以参考 java.util.Observable 和 java.util.Observer 这两个类。而且观察者模式不仅可以是subject主动推,也可以observer主动拉去数据,这也是为什么Event对象一般都包含Subject对象的原因。