【设计模式】观察者模式 在java中的应用
引言
观察者模式的定义
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现事件处理系统。
通过观察者模式,主题(Subject)和观察者(Observer)之间的耦合度降低了。主题只需维护一个观察者列表,并负责通知观察者,而不需要关心观察者的具体实现。
观察者模式的应用场景
观察者模式广泛应用于需要事件通知的场景,以下是一些典型的应用场景:
-
GUI框架中的事件处理:
- 在图形用户界面(GUI)中,按钮、文本框等控件的事件处理通常使用观察者模式。例如,按钮的点击事件可以通知多个监听器执行相应的操作。
-
数据模型与视图的同步:
- 在MVC(Model-View-Controller)架构中,模型(Model)是主题,视图(View)是观察者。当模型的数据发生变化时,视图需要自动更新以反映最新的数据。
-
发布-订阅系统:
- 在消息系统中,发布者(Publisher)和订阅者(Subscriber)之间通常使用观察者模式。发布者发布消息,所有订阅了该消息的订阅者都会收到通知并处理消息。
-
日志系统:
- 在日志系统中,可以将不同的日志记录器(如文件记录器、控制台记录器)作为观察者,日志事件发生时,所有的日志记录器都会收到通知并记录日志。
观察者模式的基本概念
主题(Subject)和观察者(Observer)的关系
在观察者模式中,主要涉及两个角色:主题(Subject)和观察者(Observer)。
-
主题(Subject):
- 主题是被观察的对象。它维护了一组观察者,并在自身状态发生变化时通知这些观察者。
- 主题通常提供以下方法:
registerObserver(Observer o)
:注册一个观察者。removeObserver(Observer o)
:移除一个观察者。notifyObservers()
:通知所有注册的观察者。
-
观察者(Observer):
- 观察者是观察主题的对象。当主题的状态发生变化时,观察者会收到通知并进行相应的更新。
- 观察者通常实现一个
update
方法,用于接收主题的通知并更新自身状态。
观察者模式的优缺点
优点
-
解耦:
- 观察者模式将观察者与主题解耦,使得它们可以独立变化。主题不需要知道观察者的具体实现,只需通过接口进行通知。
-
灵活性:
- 可以在运行时动态添加或移除观察者,增强了系统的灵活性和可扩展性。
-
符合开闭原则:
- 观察者模式使得系统易于扩展。当需要增加新的观察者时,不需要修改现有的主题代码,只需实现新的观察者并注册到主题中即可。
缺点
-
可能导致性能问题:
- 当观察者数量较多时,通知所有观察者可能会导致性能问题。尤其是在观察者需要处理复杂逻辑时,整个通知过程可能会变得很慢。
-
可能导致内存泄漏:
- 如果主题维护的观察者列表没有及时清理(例如,观察者已经不再需要但没有被移除),可能会导致内存泄漏。
-
不确定的通知顺序:
- 通常情况下,观察者的通知顺序是不确定的。如果不同的观察者对通知的顺序有依赖性,可能会导致问题。
Java中的观察者模式实现
Java内置的观察者模式
Java 提供了一套内置的观察者模式实现,通过 java.util.Observer
接口和 java.util.Observable
类来实现。
java.util.Observer
接口
Observer
接口只有一个方法,需要观察者实现:
public interface Observer {
void update(Observable o, Object arg);
}
java.util.Observable
类
Observable
类提供了一些方法来管理和通知观察者:
public class Observable {
// 添加观察者
public synchronized void addObserver(Observer o) { ... }
// 删除观察者
public synchronized void deleteObserver(Observer o) { ... }
// 通知所有观察者
public void notifyObservers() { ... }
// 通知所有观察者,并传递参数
public void notifyObservers(Object arg) { ... }
// 标记状态已改变
protected synchronized void setChanged() { ... }
// 清除已改变标记
protected synchronized void clearChanged() { ... }
// 检查状态是否已改变
public synchronized boolean hasChanged() { ... }
// 获取观察者数量
public synchronized int countObservers() { ... }
}
示例代码
import java.util.Observable;
import java.util.Observer;
// 具体的主题类
class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void measurementsChanged() {
setChanged();
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
// 具体的观察者类
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Observable observable) {
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
// 测试代码
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
}
}
自定义实现观察者模式
虽然 Java 内置的观察者模式实现已经很方便,但有时我们需要自定义实现以满足特定需求。以下是一个自定义实现的示例:
自定义接口和类
import java.util.ArrayList;
import java.util.List;
// 观察者接口
interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 主题接口
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 具体的主题类
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 o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@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();
}
}
// 具体的观察者类
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
// 测试代码
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
}
}
具体代码示例
使用 java.util.Observer
和 java.util.Observable
的示例
首先,我们来看一个使用 Java 内置的 Observer
和 Observable
来实现观察者模式的示例。
主题类(Observable)
import java.util.Observable;
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public void measurementsChanged() {
setChanged();
notifyObservers();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
观察者类(Observer)
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
测试类
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
weatherData.addObserver(currentDisplay);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
自定义实现观察者模式的示例
接下来,我们来看一个自定义实现观察者模式的示例。
主题接口
import java.util.ArrayList;
import java.util.List;
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
观察者接口
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
具体的主题实现类
public 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 o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public void measurementsChanged() {
notifyObservers();
}
}
具体的观察者实现类
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
测试类
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
weatherData.registerObserver(currentDisplay);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
通过这两个示例,我们可以看到如何使用 Java 内置的 Observer
和 Observable
实现观察者模式,以及如何自定义实现观察者模式。
观察者模式在实际项目中的应用
典型应用场景
观察者模式在实际项目中有许多典型的应用场景,包括但不限于:
- 事件处理系统:在 GUI 工具包(如 Java Swing)中,观察者模式用于监听用户事件(如按钮点击、文本输入等)。
- 日志系统:在应用程序中,日志记录器可以作为观察者,监听应用程序的状态变化并记录相关信息。
- 通知系统:在社交网络、邮件系统或消息推送系统中,观察者模式用于通知用户关于某些事件的发生。
- 数据同步:在分布式系统中,观察者模式用于保证数据的一致性,当数据发生变化时,所有的副本都会同步更新。
观察者模式在 MVC 架构中的应用
MVC(Model-View-Controller)架构是一个非常经典的设计模式,广泛应用于各种软件开发中。观察者模式在 MVC 架构中扮演了重要角色,特别是在 Model 和 View 之间的交互中。
MVC 架构概述
- Model:负责数据和业务逻辑的处理。
- View:负责数据显示和用户界面的呈现。
- Controller:负责接收用户输入并调用 Model 和 View 来完成用户请求。
在 MVC 中,Model 作为主题(Subject),View 作为观察者(Observer)。当 Model 中的数据发生变化时,View 会自动更新,以反映新的数据状态。
示例代码
我们以一个简单的股票价格更新系统为例,展示观察者模式在 MVC 架构中的应用。
Model 类
import java.util.Observable;
public class StockData extends Observable {
private String stockSymbol;
private float stockPrice;
public StockData(String stockSymbol) {
this.stockSymbol = stockSymbol;
}
public void setStockPrice(float stockPrice) {
this.stockPrice = stockPrice;
stockPriceChanged();
}
public void stockPriceChanged() {
setChanged();
notifyObservers();
}
public String getStockSymbol() {
return stockSymbol;
}
public float getStockPrice() {
return stockPrice;
}
}
View 类
import java.util.Observable;
import java.util.Observer;
public class StockDisplay implements Observer {
private Observable stockData;
private String stockSymbol;
private float stockPrice;
public StockDisplay(Observable stockData) {
this.stockData = stockData;
stockData.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof StockData) {
StockData stockData = (StockData) o;
this.stockSymbol = stockData.getStockSymbol();
this.stockPrice = stockData.getStockPrice();
display();
}
}
public void display() {
System.out.println("Stock: " + stockSymbol + " Price: " + stockPrice);
}
}
Controller 类
public class StockController {
private StockData stockData;
public StockController(StockData stockData) {
this.stockData = stockData;
}
public void updateStockPrice(float newPrice) {
stockData.setStockPrice(newPrice);
}
}
测试代码
public class StockMarket {
public static void main(String[] args) {
StockData stockData = new StockData("AAPL");
StockDisplay stockDisplay = new StockDisplay(stockData);
StockController stockController = new StockController(stockData);
stockController.updateStockPrice(150.0f);
stockController.updateStockPrice(155.0f);
}
}
小结
观察者模式的优缺点总结
优点
- 松耦合:观察者模式使得观察者和主题之间的耦合度降低。主题不需要知道观察者的具体实现,只需要知道它们实现了观察者接口。
- 灵活性:可以在运行时动态添加和移除观察者,提供了很大的灵活性。
- 扩展性:可以很容易地添加新的观察者而不影响现有的系统。
- 一致性:当主题的状态发生变化时,所有的观察者都会自动接收到通知,保持数据的一致性。
缺点
- 性能开销:如果有大量的观察者,通知所有观察者可能会影响性能。
- 复杂性增加:管理观察者列表和通知机制会增加系统的复杂性,特别是在处理并发问题时。
- 潜在的内存泄漏:如果观察者没有正确地解除注册,可能会导致内存泄漏。
使用观察者模式的最佳实践
- 明确职责:确保主题和观察者各自的职责明确,主题只负责状态的管理和通知,观察者负责响应和处理通知。
- 避免过度使用:不要滥用观察者模式,尤其是在简单的场景中。过度使用会增加系统的复杂性。
- 处理并发问题:在多线程环境中,确保对观察者列表的操作是线程安全的,以避免并发问题。
- 解除注册:在适当的时候(如观察者不再需要接收通知时)确保观察者正确地解除注册,以避免内存泄漏。
- 通知优化:在大量观察者的情况下,可以考虑批量通知或延迟通知,以优化性能。
原文地址:https://blog.csdn.net/qq_42320804/article/details/144332740
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!