一、观察者模式介绍
观察者(Observer Pattern)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
观察者模式的角色:
- 抽象主题(
Subject
)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。- 具体主题(
Concrete Subject
)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。- 抽象观察者(
Observer
)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。- 具体观察者(
Concrete Observer
)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。此处我们有一个诉求:
- 我们有各种不同的网站需要从天气数据中心,实时获取气温与空气质量的信息。
- 使用观察者模式,当数据发生变更,第一时间推送给网站。
二、观察者模式使用
2.1 示例关系:
2.2 代码实现:
- 观察者
/* *
* 1. 抽象观察者(Observer)。
*/
interface Observer {
/* *
* 更新气温和空气质量。
*/
void update(Double temperature, String airQuality);
/* *
* 获取当前观察者名。
*/
String getName();
}
/* *
* 2. 百度网站类实现抽象观察者接口(ConcreteObserver)。
*/
class BaiduWebsite implements Observer {
/* *
* 气温温度。
*/
private Double temperature;
/* *
* 空气质量。
*/
private String airQuality;
@Override
public void update(Double temperature, String airQuality) {
this.temperature = temperature;
this.airQuality = airQuality;
showWeatherInfo();
}
@Override
public String getName() {
return "百度网站";
}
private void showWeatherInfo() {
System.out.println(getName() + " 显示温度是" + temperature + "℃");
System.out.println(getName() + " 显示空气质量是" + airQuality);
}
}
/* *
* 3. 新浪网站类实现抽象观察者接口(ConcreteObserver)。
*/
class SinaWebsite implements Observer {
private Double temperature;
private String airQuality;
@Override
public void update(Double temperature, String airQuality) {
this.temperature = temperature;
this.airQuality = airQuality;
showWeatherInfo();
}
@Override
public String getName() {
return "新浪网站";
}
private void showWeatherInfo() {
System.out.println(getName() + " 显示温度是" + temperature + "℃");
System.out.println(getName() + " 显示空气质量是" + airQuality);
}
}
- 被观察者
/* *
* 4. 主题接口-抽象被观察者(Subject)。
*/
interface Subject {
/* *
* 注册观察者。
*/
void registryObserver(Observer observer);
/* *
* 移除观察者。
*/
void removeObserver(Observer observer);
/* *
* 通知观察者。
*/
void notifyObservers();
}
/* *
* 5. 天气数据中心类实现主题接口-具体被观察者(ConcreteSubject)。
*/
class WeatherDataCenter implements Subject {
private Double temperature;
private String airQuality;
/* *
* 用于存放观察者的集合。
*/
List<Observer> observers;
/* *
* 构造器。
*/
public WeatherDataCenter() {
observers = new ArrayList<>();
}
@Override
public void registryObserver(Observer observer) {
observers.add(observer);
System.out.println(observer.getName() + " 注册观察者资格成功!");
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
System.out.println(observer.getName() + " 取消观察者资格成功!");
}
/* *
* 设置天气数据方法。
* 调用则说明数据发生变更。
*/
public void setWeatherData(Double temperature, String airQuality) {
this.temperature = temperature;
this.airQuality = airQuality;
dataChange();
}
/* *
* 数据变更时,通知观察者。
*/
private void dataChange() {
notifyObservers();
}
@Override
public void notifyObservers() {
// 将当前观察者集逐个赋值更新。
for (Observer observer : observers) {
observer.update(this.temperature, this.airQuality);
}
}
}
- 客户端调用
/* *
* 6. 客户端调用。
*/
public class Client {
public static void main(String[] args) {
// 创建天气数据中心(创建被观察者)。
WeatherDataCenter weatherDataCenter = new WeatherDataCenter();
// 将百度和新浪网站进行注册(注册观察者)。
weatherDataCenter.registryObserver(new BaiduWebsite());
weatherDataCenter.registryObserver(new SinaWebsite());
// 百度网站 注册观察者资格成功!
// 新浪网站 注册观察者资格成功!
System.out.println();
weatherDataCenter.setWeatherData(21.3D, "优");
// 百度网站 显示温度是21.3℃
// 百度网站 显示空气质量是优
// 新浪网站 显示温度是21.3℃
// 新浪网站 显示空气质量是优
System.out.println(">>>>>>天气数据信息发生变化>>>>>>");
weatherDataCenter.setWeatherData(20.7D, "良");
// 百度网站 显示温度是20.7℃
// 百度网站 显示空气质量是良
// 新浪网站 显示温度是20.7℃
// 新浪网站 显示空气质量是良
}
}
三、观察者模式总结
优点:
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
- 目标与观察者之间建立了一套触发机制。
缺点:
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
应用场景:
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
- 实现类似广播机制的功能,不需要知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。
- 多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。
JDK
中的Observable
类使用到了该模式。
四、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。