设计模式之观察者模式

观察者模式

定义

设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。

( 引用维基百科 )

观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

( 引用百度百科 )

白话文

出版者+订阅者=观察者模式。主题对象管理某些数据,当主题内的数据改变,就会通知观察者。观察者已经订阅(注册)主题以便在主题数据改变时能够收到更新。

类图

observer-pattern-uml.png

角色解析

  • Subject

    观察对象。定义了注册、删除、通知观察者接口。

  • ConcreteSubject

    观察对象具体实现类。

  • Observer

    所有潜在的观察者必须实现观察者接口。当主题状态改时它被调用。

  • ConcreteObserver

    具体的观察者可以是实现此接口的任意类。观察者必须注册到具体主题,以便接收更新。

实现

observer-main-pattern.png

1. 定义主题接口

/**
 * 主题接口
 * 注册、通知、移除
 */
public interface Subject {
    /**
     * 注册观察者
     * @param o
     */
    void registerObserver(Observer o);

    /**
     * 移除观察者
     * @param o
     */
    void removeObserver(Observer o);

    /**
     * 当主题状态改变时,这个方法会被调用,以通知所有的观察者
     */
    void notifyObservers();
}

2. 主题接口实现类

/**
 * 主题接口实现类
 */
public class WeatherData implements Subject{
    /**
     * 温度
     */
    private float temperature;
    /**
     * 湿度
     */
    private float humidity;
    /**
     * 压力
     */
    private float pressure;

    /**
     * 观察者列表
     */
    private List<Observer> observerList;
    
    public WeatherData() {
        observerList = new ArrayList<>();
    }

    /**
     * 注册观察者对象
     * @param o
     */
    @Override
    public void registerObserver(Observer o) {
        observerList.add(o);
    }

    /**
     * 解除观察者对象
     * @param o
     */
    @Override
    public void removeObserver(Observer o) {
        observerList.remove(o);
    }

    /**
     * 通知所有观察者
     */
    @Override
    public void notifyObservers() {
        for (Observer observer : observerList) {
            observer.update(temperature, humidity, pressure);
        }
    }

    /**
     * 当测试值改变时,调用通知方法
     */
    public void measurementsChange() {
        notifyObservers();
    }

    /**
     * 此方法模拟测量值改变
     */
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChange();
    }
}

3. 观察者接口

/**
 * 定义观察者共同行为
 */
public interface Observer {
    /**
     * 所有观察者必须实现接口。当主题值改变时,会调用此方法
     * @param temp
     * @param humidity
     * @param pressure
     */
    void update(float temp, float humidity, float pressure);
}

4. 观察者具体实现类

/**
 * 当前观察者实现类之一
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement{
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }

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

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }
}
/**
 * 当前观察者实现类之二
 */
public class TempConditionDisplay implements Observer, DisplayElement{
    private float temp;
    public TempConditionDisplay(Subject subject) {
        subject.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("Temp Condition Display,Current temp is " + temp);
    }

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

5. 其他接口及实现类

/**
 * 布告板显示接口
 */
public interface DisplayElement {
    void display();
}

6. Main方法

public class M {
    public static void main(String[] args) {
        // 创建主题类
        WeatherData weatherData = new WeatherData();
        // 创建观察者并把具体主题引入传入
        // 观察者之一
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        // 观察者之二
        TempConditionDisplay tempConditionDisplay = new TempConditionDisplay(weatherData);
       
        // 温度变化
        weatherData.setMeasurements(1F, 3F, 4F);
    }
}

总结

  1. 观察者模式提供了一种设计对象,让主题和观察者之间松耦合。主题只知道观察者实现了某个接口,并不需要知道观察者的具体类是谁、做了些什么或其他任何细节。

  2. 任何时候我们都可以增加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的对象列表。可以动态新增、删除、替换观察者,而其他观察者不受影响。只要它们之间的接口仍被遵守,我们就可以自由改变它们。松耦合的设计能让我们建立弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。

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

  4. 观察者模式可以实现两种动作。

  5. 注意: 不要依赖于观察者被通知的次序。

  6. Java有内置的观察者模式。包含最基本的Observer接口与Observable。但是Observable是一个而非接口,限制了它的使用和复用。自Java1.9废弃。

     * This class and the {@link Observer} interface have been deprecated.
     * The event model supported by {@code Observer} and {@code Observable}
     * is quite limited, the order of notifications delivered by
     * {@code Observable} is unspecified, and state changes are not in
     * one-for-one correspondence with notifications.
     * For a richer event model, consider using the
     * {@link java.beans} package.  For reliable and ordered
     * messaging among threads, consider using one of the concurrent data
     * structures in the {@link java.util.concurrent} package.
     * For reactive streams style programming, see the
     * {@link java.util.concurrent.Flow} API.
    
  7. 如果一下被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知会花费很多时间。

  8. 如果在观察者和观察目标之间有循环依赖的话,会触发它们之间的循环引用,进而导致系统崩溃。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值