定义
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
以下是观察者模式的主要特点和定义:
主要角色
-
Subject(主题) :
- 知道它的观察者。可以有任意多个观察者观察同一个主题。
- 提供注册和删除观察者对象的接口。
- 当主题的状态发生变化时,通知所有注册的观察者。
-
Observer(观察者) :
- 为那些在主题发生变化时需要被通知的对象定义一个更新接口。
-
ConcreteSubject(具体主题) :
- 将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
-
ConcreteObserver(具体观察者) :
- 实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
业务
假设我们有一个气象站,它可以测量温度、湿度和气压等数据。当气象数据发生变化时,需要通知多个显示设备,如显示屏、手机应用等。我们可以使用观察者模式来实现这个功能。
classDiagram
class Observer {
+update(float, float, float) : void
}
class Display {
-float temperature
-float humidity
-float pressure
+update(float, float, float) : void
+display() : void
}
class Subject {
+registerObserver(Observer) : void
+removeObserver(Observer) : void
+notifyObservers() : void
}
class WeatherData {
-List<Observer> observers
-float temperature
-float humidity
-float pressure
+registerObserver(Observer) : void
+removeObserver(Observer) : void
+notifyObservers() : void
+measurementsChanged() : void
+setMeasurements(float, float, float) : void
}
Observer <|-- Display
Subject <|-- WeatherData
Observer <-- WeatherData
一、定义观察者接口(Observer)
interface Observer {
void update(float temperature, float humidity, float pressure);
}
二、定义主题接口(Subject)
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
三、实现具体主题(ConcreteSubject)
class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@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(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
四、实现具体观察者(ConcreteObserver)
class Display implements Observer {
private float temperature;
private float humidity;
private float pressure;
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
private void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity and " + pressure + " pressure.");
}
}
五、使用观察者模式
public class ObserverPatternExample {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
Display display = new Display();
weatherData.registerObserver(display);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.9f);
weatherData.removeObserver(display);
weatherData.setMeasurements(78, 60, 31.1f);
}
}
在这个例子中,WeatherData是具体主题,它实现了Subject接口,负责存储气象数据并通知观察者。Display是具体观察者,实现了Observer接口,负责接收气象数据并显示在屏幕上。通过这种方式,气象站可以将气象数据的变化通知多个显示设备,而不需要知道具体的显示设备是什么。这种设计实现了主题和观察者之间的松散耦合,使得系统更加灵活和易于维护
框架中的使用
各种消息队列
mq中的消费订阅
spring
一、事件驱动架构中的应用
Spring 的事件驱动架构基于观察者模式。可以定义事件(主题)和事件监听器(观察者)。当特定的事件发生时,Spring 会通知所有注册的监听器。
例如:
- 定义事件:
package com.example.events;
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
- 定义事件监听器:
package com.example.events;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Received custom event: " + event.getMessage());
}
}
- 触发事件:
package com.example;
import com.example.events.CustomEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.publishEvent(new CustomEvent(Main.class, "Hello from custom event!"));
}
}
在这个例子中,CustomEvent是自定义的事件,它继承自ApplicationEvent。CustomEventListener是事件监听器,实现了ApplicationListener接口。在main方法中,通过ApplicationContext触发事件,Spring 会自动通知所有注册的监听器。
总结
使用场景
-
当一个对象的状态变化需要通知其他对象,而又不希望它们之间有紧密的耦合关系时。
- 例如在图形用户界面中,一个按钮的点击事件可能需要通知多个组件进行相应的更新。
-
当一个对象的变化会引起多个对象的变化时。
- 比如在股票交易系统中,股票价格的变化会通知多个显示股票价格的界面进行更新。
优点
-
实现了主题和观察者之间的松散耦合。
- 主题只需要知道有观察者存在,而不需要知道具体是哪些观察者。观察者只需要实现一个更新接口,而不需要了解主题的具体实现。
-
可以方便地添加和删除观察者。
- 主题只需要通过注册和删除接口来管理观察者,而不需要修改其他代码。
-
支持广播通信。
- 主题可以同时通知多个观察者,而不需要分别通知每个观察者。
缺点
- 如果一个主题有很多观察者,通知所有观察者可能会花费很多时间。
- 如果观察者和主题之间存在循环依赖,可能会导致系统死锁。
- 观察者模式可能会导致系统的复杂性增加,特别是当有很多观察者和主题时。