观察者模式(Observer Pattern)是一种行为型设计模式,其主要目的是定义一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象状态发生变化时,所有依赖于它的观察者都得到通知并被自动更新。观察者模式使得主题对象和观察者对象之间保持松耦合,以便可以灵活地扩展和重用。
在观察者模式中发生改变的对象称为观察目标 ,而被通知的对象称为观察者,一个观察目标可以应对多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展.
比如我们生活中的等待红绿灯的汽车,红绿灯就是一个观察目标,而所有等待的汽车就是观察者。
主要角色:
-
主题(Subject): 也就是抽象的被观察者,负责维护一系列观察者对象,并通知它们状态的变化。
-
具体主题(Concrete Subject): 也就是具体的被观察者对象,实现了主题接口,负责状态的存储和变化,当状态发生变化时通知观察者。
-
观察者(Observer): 定义了一个更新接口,用于接收主题对象的通知。
-
具体观察者(Concrete Observer): 实现了观察者接口,当接收到主题对象的通知时进行相应的更新操作。
示例:
一个气象站的例子,气象站可以实时测量温度、湿度和气压,并通知观察者(如手机、电视等设备)。
java
package com.luke.designpatterns.observerPattern;
import java.util.ArrayList;
import java.util.List;
// 抽象的被观察者
interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体的被观察者 - 气象站
class WeatherStation implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherStation() {
this.observers = new ArrayList<>();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
notifyObservers();
}
@Override
public void addObserver(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);
}
}
}
// 抽象的观察者
interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 具体观察者 - 手机
class PhoneDisplay implements Observer {
@Override
public void update(float temperature, float humidity, float pressure) {
System.out.println("Phone Display: Temperature - " + temperature + "°C, Humidity - " + humidity + "%");
}
}
// 具体观察者 - 电视
class TVDisplay implements Observer {
@Override
public void update(float temperature, float humidity, float pressure) {
System.out.println("TV Display: Pressure - " + pressure + "hPa");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建被观察者
WeatherStation weatherStation = new WeatherStation();
// 添加观察者
Observer phoneDisplay = new PhoneDisplay();
Observer tvDisplay = new TVDisplay();
weatherStation.addObserver(phoneDisplay);
weatherStation.addObserver(tvDisplay);
// 模拟气象站测量并通知观察者
weatherStation.setMeasurements(25.5f, 60.0f, 1012.5f);
}
}
在这个例子中,WeatherStation
是具体的被观察者,负责测量气象信息并通知观察者。Observer
是观察者接口,定义了更新方法。PhoneDisplay
和 TVDisplay
是具体观察者,实现了更新方法,并在接收到通知时进行相应的操作。
客户端代码创建了一个气象站作为主题,添加了手机和电视作为观察者。当气象信息发生变化时,主题通知观察者进行更新。观察者模式使得主题和观察者之间的关系变得灵活,可以方便地增加、删除观察者,同时确保主题对象不需要知道观察者的具体细节。
适用场景
观察者模式适用于以下场景:
- 对象间存在一对多的依赖关系: 当一个对象的变化需要通知多个其他对象时,观察者模式非常有用,因为它建立了一种松散耦合的关系。
比如图形界面中的事件处理。考虑一个按钮对象作为被观察者,而多个UI组件(比如文本框、复选框等)作为观察者。当按钮被点击时,所有注册的UI组件都能够接收到通知并执行相应的操作。
- 抽象模型有两个方面,其中一个依赖于另一方面: 当一个对象的状态变化需要影响到另一个对象,但又希望保持独立性时,可以考虑使用观察者模式。
比如股票市场。股票价格作为被观察者,而图表和报价服务作为观察者。当股票价格变化时,图表和报价服务能够接收到通知并更新显示的数据。
- 系统需要分布式事件处理: 观察者模式在实现分布式事件处理系统时很有用,因为它允许对象之间通过事件通知进行通信,而无需直接了解彼此的存在。
比如在线协作编辑器。文档的变化作为被观察者,而不同用户的编辑器作为观察者。通过观察者模式,文档的变化可以实时地通知到所有其他用户的编辑器,实现协同编辑功能。
- 动态更新情况: 当一个对象的改变需要动态地通知其他对象,并且不希望知道具体通知哪些对象时,观察者模式提供了一种灵活的解决方案。
比如一个天气应用程序。天气数据作为被观察者,而不同的天气组件(比如温度显示、风速显示等)作为观察者。当天气数据发生变化时,所有注册的天气组件都能够动态更新显示最新的天气信息。
总体来说,观察者模式适用于需要解耦对象之间依赖关系、实现松散耦合、并提供灵活性和可扩展性的情况。