当前位置: 首页 > news >正文

Android 观察者模式(OBSERVER)应用详解

文章目录

    • 1、观察者模式设计初衷
      • 1.1. 解耦对象之间的依赖关系
      • 1.2. 允许动态的依赖关系
      • 1.3. 自动通知和更新
      • 1.4 设计初衷的详细说明
        • 1. 对象之间的解耦
        • 2. 动态依赖关系
        • 3. 自动更新
    • 2、实现细节
      • 2.1. Subject 接口和实现
      • 2.2. Observer 接口和实现
      • 2.3. 主类
    • 3、主要角色
    • 4、关系示意图
    • 5、Java 实现示例
      • 使用 Java 内置的 Observable 和 Observer
        • Observable 类
        • Observer 接口
        • 主类
    • 6、自定义实现 Observer 和 Subject
      • 6.1 Subject 接口
      • 6.2 Observer 接口
      • 主类
    • 7、优缺点分析
      • 7.1 优点
      • 7.2 缺点
    • 8、总结

1、观察者模式设计初衷

1.1. 解耦对象之间的依赖关系

在软件系统中,对象之间往往需要相互依赖。例如,视图对象依赖于数据模型对象,来显示最新的数据状态。直接的依赖关系会导致高耦合,增加维护的复杂性和难度。

设计初衷

  • 松耦合设计:观察者模式通过抽象层(Observer接口)来解耦具体的对象。被观察者(Subject)只知道有观察者存在,不需要了解观察者的具体实现。
  • 易于扩展:通过接口解耦,可以方便地增加新的观察者而不影响现有的代码,实现开闭原则(对扩展开放,对修改关闭)。

示例
一个天气预报系统中,WeatherData类作为被观察者,而CurrentConditionsDisplayStatisticsDisplay等作为观察者。WeatherData不需要了解具体显示类的实现,只需知道它们实现了Observer接口。

1.2. 允许动态的依赖关系

在运行时,系统的依赖关系可能需要动态变化。例如,用户可能会在运行时订阅或取消订阅某些数据。

设计初衷

  • 动态注册和注销观察者:观察者模式允许在运行时动态地添加和移除观察者,灵活应对变化的需求。
  • 灵活性和动态性:被观察者可以在任何时候通知其观察者,无需事先确定所有的观察者。

示例
在一个股票交易系统中,用户可以随时订阅或取消订阅股票行情。StockData类作为被观察者,当用户订阅时,将其客户端注册为观察者,当用户取消订阅时,将其从观察者列表中移除。

1.3. 自动通知和更新

在一些实时更新的系统中,依赖对象需要在状态变化时自动更新。例如,当数据模型改变时,视图对象需要自动更新以反映最新的数据。

设计初衷

  • 自动通知:被观察者在其状态改变时,自动通知所有注册的观察者,避免手动更新带来的复杂性。
  • 一致性:确保所有依赖于被观察者的对象在状态变化后保持一致性,避免数据不同步问题。

示例
在一个气象站应用中,当气象数据变化时,WeatherData会通知所有的显示组件(观察者),以便它们更新显示最新的气象数据。

1.4 设计初衷的详细说明

1. 对象之间的解耦

问题
在软件系统中,不同的对象之间往往存在依赖关系。例如,一个数据模型对象(Model)和多个视图对象(View)。当数据模型发生变化时,视图对象需要随之更新。如果每个视图对象都直接依赖于数据模型对象,并且在数据模型中直接调用视图对象的方法,这将导致系统的高耦合,增加维护难度。

解决方案
通过观察者模式,被观察者(Subject)和观察者(Observer)之间的关系是松耦合的。被观察者只知道有一组观察者实现了某个接口,而不知道具体是什么对象。观察者也只知道被观察者的状态发生了变化,而不知道变化的具体原因。这样就实现了对象之间的解耦。

示例
在一个气象站应用中,气象数据(WeatherData)是被观察者,而各种显示元素(如当前条件显示、统计显示等)是观察者。气象数据只需要通知观察者数据发生了变化,而具体如何显示是观察者的事情。

2. 动态依赖关系

问题
系统在运行时可能需要动态地添加或移除依赖关系。例如,在一个实时股票行情系统中,不同的客户端可能在不同的时间段订阅或取消订阅股票行情。

解决方案
观察者模式允许在运行时动态地注册(添加)或注销(移除)观察者。这使得系统能够灵活地响应不同的需求和变化,而无需在设计时确定所有的依赖关系。

示例
在一个聊天应用中,当用户加入一个群组时,用户的客户端会成为群组消息的观察者。当用户离开群组时,用户的客户端会被移除出群组消息的观察者列表。

3. 自动更新

问题
当一个对象的状态变化时,依赖它的所有对象需要同步更新。例如,在一个数据驱动的应用中,当数据模型变化时,所有依赖于该模型的视图都需要更新。

解决方案
通过观察者模式,当被观察者的状态发生变化时,它会通知所有注册的观察者进行更新。这样,所有依赖于被观察者的对象都能够自动更新,保持系统的一致性。

示例
在一个股票交易应用中,当股票价格变化时,所有显示该股票价格的视图都会自动更新,以显示最新的价格。

2、实现细节

2.1. Subject 接口和实现

import java.util.ArrayList;
import java.util.List;public 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<>();}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic 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();}
}

2.2. Observer 接口和实现

public interface Observer {void update(float temperature, float humidity, float pressure);
}class CurrentConditionsDisplay implements Observer {private float temperature;private float humidity;private Subject weatherData;public CurrentConditionsDisplay(Subject weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}@Overridepublic 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");}
}

2.3. 主类

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);weatherData.setMeasurements(78, 90, 29.2f);}
}

3、主要角色

  1. Subject(被观察者/主题)

    • 保存观察者的列表。
    • 向观察者发送通知。
    • 提供注册和移除观察者的方法。
  2. Observer(观察者)

    • 接收通知并更新状态。
    • 包含一个更新方法,用于被主题通知。

4、关系示意图

+----------+        +-----------+
|  Subject |<------>|  Observer |
+----------+        +-----------+
| attach() |        | update()  |
| detach() |        +-----------+
| notify() |
+----------+

5、Java 实现示例

使用 Java 内置的 Observable 和 Observer

Java 提供了内置的 java.util.Observable 类和 java.util.Observer 接口。

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;public CurrentConditionsDisplay(Observable observable) {observable.addObserver(this);}@Overridepublic void update(Observable obs, Object arg) {if (obs instanceof WeatherData) {WeatherData weatherData = (WeatherData) obs;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);weatherData.setMeasurements(78, 90, 29.2f);}
}

6、自定义实现 Observer 和 Subject

在现代Java编程中,更推荐使用自定义接口和类实现观察者模式,因为 java.util.Observable 已被标记为过时。

6.1 Subject 接口

import java.util.ArrayList;
import java.util.List;public 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<>();}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {int i = observers.indexOf(o);if (i >= 0) {observers.remove(i);}}@Overridepublic 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();}
}

6.2 Observer 接口

public interface Observer {void update(float temp, float humidity, float pressure);
}class CurrentConditionsDisplay implements Observer {private float temperature;private float humidity;@Overridepublic 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);}
}

7、优缺点分析

7.1 优点

  1. 松耦合

    • 观察者和被观察者之间是松耦合的,便于维护和扩展。
  2. 动态注册和注销

    • 可以在运行时动态添加或移除观察者,灵活应对变化的需求。
  3. 自动通知

    • 被观察者状态变化时,会自动通知所有观察者,保持系统的一致性。

7.2 缺点

  1. 通知顺序不确定

    • 观察者接收通知的顺序不确定,可能导致一些时序问题。
  2. 内存泄漏

    • 如果被观察者没有正确地移除不再需要的观察者,可能导致内存泄漏。
  3. 性能问题

    • 如果观察者数量过多,通知过程可能比较耗时,影响性能。

8、总结

观察者模式的设计初衷主要在于解决对象之间的耦合问题,允许动态依赖关系,并自动通知依赖对象进行更新。这些特性使得观察者模式在需要松耦合、动态依赖和自动更新的场景中非常有用。然而,开发者在使用观察者模式时,也需要注意内存泄漏、性能开销等问题,采取适当的优化措施,如使用弱引用和异步通知,来提升系统的健壮性和效率。

通过合理使用观察者模式,可以使系统更加灵活、可维护性更高,并且能够有效地响应变化。这种模式在GUI应用、实时数据更新、发布-订阅系统等场景中得到了广泛应用,是软件设计中的重要模式之一。

欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力

在这里插入图片描述

相关文章:

  • Spring与Netty底层源码解析
  • 一个基于HOOK机制的微信机器人
  • 论文阅读--ViLD
  • 力扣226. 翻转二叉树(DFS的两种思路)
  • 开源模型应用落地-模型量化-Qwen1.5-7B-Chat-GPTQ-Int8(一)
  • 初见flyway
  • MongoDB 和 MySQL 的对比
  • Flutter 页面布局 Flex Expanded弹性布局
  • 谷歌上架,个人号比企业号好上?“14+20”封测如何解决,你知道了吗
  • 基于RV1126的AI网络摄像机AHD、CVBS、HDMI接口的区别有哪些?支持8路AHD摄像头,支持AI实时分析
  • Python-温故知新
  • 2024上海国际化工自动化仪器仪表展览会
  • 数据结构_栈在括号匹配中的应用_代码
  • 使用位掩码的权限设计
  • 前端实现打印功能
  • 【译】JS基础算法脚本:字符串结尾
  • [译] React v16.8: 含有Hooks的版本
  • 2017-09-12 前端日报
  • css系列之关于字体的事
  • ES6 ...操作符
  • Mybatis初体验
  • php面试题 汇集2
  • Redis中的lru算法实现
  • Ruby 2.x 源代码分析:扩展 概述
  • 编写高质量JavaScript代码之并发
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 前端学习笔记之观察者模式
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 写代码的正确姿势
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • 组复制官方翻译九、Group Replication Technical Details
  • ​ArcGIS Pro 如何批量删除字段
  • # Java NIO(一)FileChannel
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (11)MATLAB PCA+SVM 人脸识别
  • (13)Hive调优——动态分区导致的小文件问题
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (补充)IDEA项目结构
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (三)Honghu Cloud云架构一定时调度平台
  • (转)Linux下编译安装log4cxx
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (转)Windows2003安全设置/维护
  • (转)德国人的记事本
  • (转)关于多人操作数据的处理策略
  • .form文件_一篇文章学会文件上传
  • .net core 控制台应用程序读取配置文件app.config
  • .net 流——流的类型体系简单介绍
  • .net实现客户区延伸至至非客户区
  • @Async注解的坑,小心
  • @media screen 针对不同移动设备