Java 中的观察者模式:精通 Java 应用程序中的反应式接口
约 4 分钟
也称为
- 依赖项
观察者设计模式的意图
Java 中的观察者模式定义了对象之间的一对多关系,确保当一个对象更新其状态时,所有依赖的观察者都会被自动通知并更新,从而增强系统的响应性和模块化。
观察者模式的详细解释以及现实世界中的例子
现实世界中的例子
在现实世界的例子中,考虑一个新闻机构系统,其中该机构(主题)发布新闻文章,多个新闻媒体(观察者)订阅以接收更新。每当新闻机构发布新文章时,它会自动通知所有已订阅的新闻媒体。然后,这些媒体可以更新他们的平台(例如网站、电视广播或报纸)以显示最新新闻。这确保了所有订阅者都能获取最新信息,而无需新闻机构了解每个媒体更新过程的具体细节。这将新闻机构与订阅者解耦,从而在处理更新方式上提高灵活性和模块化。
简单来说
实现观察者接口以主动监控和响应 Java 应用程序中的状态更改,提高事件驱动编程的效率。
维基百科说
观察者模式是一种软件设计模式,其中一个对象(称为主题)维护一个其依赖项(称为观察者)的列表,并在任何状态更改时自动通知它们,通常通过调用它们的方法。
Java 中观察者模式的编程示例
在一个遥远的地方,居住着霍比特人和兽人。他们两个都经常待在户外,所以他们密切关注天气变化。可以说,他们一直在观察天气。
让我们先介绍 `WeatherObserver` 接口以及我们的种族 `Orcs` 和 `Hobbits`。
public interface WeatherObserver {
void update(WeatherType currentWeather);
}
@Slf4j
public class Orcs implements WeatherObserver {
@Override
public void update(WeatherType currentWeather) {
LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now");
}
}
@Slf4j
public class Hobbits implements WeatherObserver {
@Override
public void update(WeatherType currentWeather) {
switch (currentWeather) {
LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
}
}
}
然后是不断变化的 `Weather`。
@Slf4j
public class Weather {
private WeatherType currentWeather;
private final List<WeatherObserver> observers;
public Weather() {
observers = new ArrayList<>();
currentWeather = WeatherType.SUNNY;
}
public void addObserver(WeatherObserver obs) {
observers.add(obs);
}
public void removeObserver(WeatherObserver obs) {
observers.remove(obs);
}
/**
* Makes time pass for weather.
*/
public void timePasses() {
var enumValues = WeatherType.values();
currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
LOGGER.info("The weather changed to {}.", currentWeather);
notifyObservers();
}
private void notifyObservers() {
for (var obs : observers) {
obs.update(currentWeather);
}
}
}
以下是完整的示例在实际操作中的情况。
public static void main(String[] args) {
var weather = new Weather();
weather.addObserver(new Orcs());
weather.addObserver(new Hobbits());
weather.timePasses();
weather.timePasses();
weather.timePasses();
weather.timePasses();
// Generic observer inspired by Java Generics and Collections by Naftalin & Wadler
LOGGER.info("--Running generic version--");
var genericWeather = new GenWeather();
genericWeather.addObserver(new GenOrcs());
genericWeather.addObserver(new GenHobbits());
genericWeather.timePasses();
genericWeather.timePasses();
genericWeather.timePasses();
genericWeather.timePasses();
}
程序输出
21:28:08.310 [main] INFO com.iluwatar.observer.Weather -- The weather changed to rainy.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Rainy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Rainy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Weather -- The weather changed to windy.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Windy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Windy weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Weather -- The weather changed to cold.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Cold weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Cold weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Weather -- The weather changed to sunny.
21:28:08.312 [main] INFO com.iluwatar.observer.Orcs -- The orcs are facing Sunny weather now
21:28:08.312 [main] INFO com.iluwatar.observer.Hobbits -- The hobbits are facing Sunny weather now
21:28:08.312 [main] INFO com.iluwatar.observer.App -- --Running generic version--
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to rainy.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Rainy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Rainy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to windy.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Windy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Windy weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to cold.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Cold weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Cold weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenWeather -- The weather changed to sunny.
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenOrcs -- The orcs are facing Sunny weather now
21:28:08.313 [main] INFO com.iluwatar.observer.generic.GenHobbits -- The hobbits are facing Sunny weather now
何时在 Java 中使用观察者模式
在以下任何情况下使用观察者模式
- 当一个抽象具有两个方面,其中一个依赖于另一个时。将这些方面封装在单独的对象中,可以让你独立地改变和重用它们。
- 当更改一个对象需要更改其他对象时,而你不知道需要更改多少个对象。
- 当一个对象应该能够通知其他对象而不会对这些对象是谁做出任何假设时。换句话说,你不希望这些对象紧密耦合。
Java 中观察者模式的现实世界应用
- java.util.Observer
- java.util.EventListener
- javax.servlet.http.HttpSessionBindingListener
- RxJava
- 模型-视图-控制器 (MVC) 框架。
- 事件处理系统。
观察者模式的优缺点
优点
- 这种 Java 设计模式促进了松散耦合,允许主题及其观察者在没有紧密依赖的情况下进行交互,从而更容易维护和扩展。
- 允许动态订阅和取消订阅观察者。
缺点
- 如果观察者没有正确地取消注册,会导致内存泄漏。
- 通知的顺序没有指定,会导致潜在的意外行为。
- 如果观察者数量过多,可能会导致性能问题。