观察者模式
观察者模式(Observer Pattern)也叫发布-订阅(Publish/Subscribe)模式,是属于行为型模式。观察者模式定义了一种对象间多对一的依赖关系,使得当被观察者状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
观察者模式的四个角色
- Subject(抽象被观察者角色): 这是一个抽象类或接口,定义了对观察者集合的操作,例如注册观察者、删除观察者和通知更新观察者信息等。
- ConcreteSubject(具体被观察者角色): 具体观察者角色有自己的属性和方法,并实现了抽象被观察者的方法。它定义了一个观察者集合,通过一些方法对观察者和观察者集合进行操作。
- Observer(抽象观察者角色): 抽象观察者通常是一个抽象类或接口,它定义了一个更新方法,当被观察者状态改变时,通过此方法更新自己的状态。
- ConcreteObserver(具体观察者角色): 具体观察者实现了抽象观察者的方法,当被观察者状态发生改变,通过
update()
方法来更新自己的状态。
举一个栗子
假设有一个气象中心负责观察天气信息,有温度、气压和湿度等。然后有一些天气软件,通过使用气象中心提供的数据放到自己的软件中作为展示天气的功能,当气象中心的数据发生变化时,气象中心又把这些更新后的数据推动给这些应用软件,来更新各个软件中的天气数据。
Subject:抽象被观察者
这个接口定义了三个方法,方法的作用在注释用可以看到。
package cn.personalweb.observer;
public interface Subject {
/**
* 注册观察者, 将观察者添加到观察者集合里
* @param observer 观察者
*/
public void registerObserver(Observer observer);
/**
* 通过观察者对象, 从集合中删除此观察者
* @param observer 观察者
*/
public void removeObserver(Observer observer);
/**
* 通知在集合中的所有观察者
*/
public void notifyObservers();
}
Observer:抽象观察者
定义了一个update()
方法,用于更新自己的状态
package cn.personalweb.observer;
public interface Observer {
/**
* 更新观察者数据
* @param temperature 温度
* @param pressure 气压
* @param humidity 湿度
*/
public void update(float temperature, float pressure, float humidity);
}
WeatherData:具体被观察者
这里的被观察者是天气数据,观察者来观察天气数据。当天气数据发生改变是,也就是setData()
方法执行时,会调用notifyObservers()
方法来改变每一个观察者的数据,也就是将最新的数据修改到观察者。
package cn.personalweb.observer;
import java.util.ArrayList;
public class WeatherData implements Subject {
/**
* 温度
*/
private float temperature;
/**
* 气压
*/
private float pressure;
/**
* 湿度
*/
private float humidity;
/**
* 观察者集合
*/
private ArrayList<Observer> observers;
public WeatherData() {
this.observers = new ArrayList<Observer>();
}
/**
* 设置数据
* @param temperature 温度
* @param pressure 气压
* @param humidity 湿度
*/
public void setData(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 当数据改变后, 调用通知所有观察者
notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(this.temperature, this.pressure, this.humidity);
}
}
}
BaiduObserver:具体百度观察者
BaiduObserver
表示一个具体的观察者,也就是一个具体的软件平台,这些具体的观察者观察天气中心。当天气中心,也就是天气数据发生改变时,会将修改后的数据推送到具体的观察者上。
package cn.personalweb.observer;
public class BaiduObserver implements Observer{
private float temperature;
private float pressure;
private float humidity;
@Override
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 修改数据之后展示数据
display();
}
/**
* 展示数据
*/
public void display(){
System.out.println("百度天气的温度是:" + temperature);
System.out.println("百度天气的气压是:" + pressure);
System.out.println("百度天气的湿度是:" + humidity);
}
}
XiaoMiObserver:具体小米观察者
功能同百度观察者。
package cn.personalweb.observer;
public class XiaoMiObserver implements Observer{
private float temperature;
private float pressure;
private float humidity;
@Override
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 修改数据之后展示数据
display();
}
/**
* 展示数据
*/
public void display(){
System.out.println("小米天气的温度是:" + temperature);
System.out.println("小米天气的气压是:" + pressure);
System.out.println("小米天气的湿度是:" + humidity);
}
}
Client:客户端
package cn.personalweb.observer;
public class Client {
public static void main(String[] args) {
// 创建WeatherData
WeatherData weatherData = new WeatherData();
// 创建观察者
XiaoMiObserver xiaoMiObserver = new XiaoMiObserver();
BaiduObserver baiduObserver = new BaiduObserver();
// 将观察者注册到 WeatherData
weatherData.registerObserver(xiaoMiObserver);
weatherData.registerObserver(baiduObserver);
//设置天气, 并通知观察者
weatherData.setData(30f, 100, 20f);
System.out.println("----------");
// 删除观察者
weatherData.removeObserver(xiaoMiObserver);
weatherData.setData(20f, 110, 22f);
}
}
输出结果
小米天气的温度是:30.0
小米天气的气压是:100.0
小米天气的湿度是:20.0
百度天气的温度是:30.0
百度天气的气压是:100.0
百度天气的湿度是:20.0
----------
百度天气的温度是:20.0
百度天气的气压是:110.0
百度天气的湿度是:22.0
使用观察者模式的优点
观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类 WeatherData 不会修改代码, 遵守了 ocp
参考资料:
尚硅谷 Java 设计模式课程笔记。