23种设计模式之观察者(Observer)模式

647 阅读3分钟

1、定义

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

2、模式结构

观察者模式由四部分组成:

  • Subject(抽象主题角色):把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以由任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
  • Concretesubject(具体主题角色):在具体主题内部状态改变时,给所有登记过的观察者发出通知。
  • Observer(抽象观察者角色):为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
  • ConcreteObserver(具体观察者角色):该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

3、实例

3.1 Subjct

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

3.2 天气数据(ConcreteSubject)

public class WeatherData implements Subject {
    // 温度
    private double temperature;
    // 湿度
    private double humidity;
    // 气压
    private double pressure;
    
    private List<Observer> observers;
    
    public WeatherData() {
        observers = new ArrayList<>();
    }
    
    public double getTemperature() {
        return temperature;
    }
    
    public double getHumidity() {
        return humidity;
    }
    
    public double getPressure() {
        return pressure;
    }
    
    public void setData(double temperature, double humidity, double pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.perssure = perssure;
        notifyObservers();
    }
    
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void removeObserver(Observer observer) {
        if (observers.contains(observer)) {
            observers.remove(observer);
        }
    }
    
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

3.3 Observer

public interface Observer {
    
    public void update();
}

3.4 当前情况(ConcrateObserver)

public class CurrentConditions implements Observer {
    
    private double temperature;
    private double humidity;
    private double pressure;
    
    private WeatherData weatherData;
    
    public CurrentConditions(WeatherData weatherData) {
        this.weatherData = weatherData;
    }
    
    @Override
    public void update() {
        this.temperature = this.weatherData.getTemperature();
        this.humidity = this.weatherData.getHumidity();
        this.pressure = this.weatherData.getPressure();
        display();
    }
    
    public void display() {
        System.out.println("***当前温度为:" + this.temperature + "***");
        System.out.println("***当前湿度为:" + this.humidity + "***");
        System.out.println("****当前气压为:" + this.pressure + "***");
    }
}
public class BaiduSite implements Observer {
    
    private double temperature;
    private double humidity;
    private double pressure;
    
    private WeatherData weatherData;
    
    public BaiduSite(WeatherData weatherData) {
        this.weatherData = weatherData;
    }
    
    @Override
    public void update() {
        this.temperature = this.weatherData.getTemperature();
        this.humidity = this.weatherData.getHumidity();
        this.pressure = this.weatherData.getPressure();
        display();
    }
    
    public void display() {
        System.out.println("***百度首页显示当前温度为:" + this.temperature + "***");
        System.out.println("***百度首页显示当前湿度为:" + this.humidity + "***");
        System.out.println("****百度首页显示当前气压为:" + this.pressure + "***");
    }
}

3.5 客户端调用

public class Client {

    public static void main(String[] args) {

        WeatherData weatherData = new WeatherData();

        CurrentConditions currentConditions = new CurrentConditions(weatherData);
        BaiduSite baiduSite = new BaiduSite(weatherData);

        weatherData.registerObserver(currentConditions);
        weatherData.registerObserver(baiduSite);

        weatherData.setData(25, 75, 40);

        System.out.println("---------------------------------------------");
        weatherData.removeObserver(currentConditions);
        weatherData.setData(30, 80, 45);
    }
}

4、适用场景

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这些方面封装在独立的对象中使它们可以独立改变地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象...,可以使用观察者模式创建一个链式触发机制。

5、在JDK中的应用

6、优缺点

6.1 优点
  • 实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
  • 在观察目标和观察者之间建立一个抽象的耦合。
  • 支持广播通信。
6.2 缺点
  • 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  • 如果在观察者和被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,可能导致系统崩溃。
  • 观察者模式没有对应的机制让观察者知道被观察对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

源代码:github.com/freedom9/de…