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<>();
    }

    @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();
    }
}

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);
    }

    @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");
    }
}

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);
    }

    @Override
    public 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<>();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    @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();
    }
}

6.2 Observer 接口

public interface Observer {
    void update(float temp, float humidity, float pressure);
}

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);
    }
}

7、优缺点分析

7.1 优点

  1. 松耦合

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

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

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

7.2 缺点

  1. 通知顺序不确定

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

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

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

8、总结

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

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

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/635487.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue02-黑马程序员学习笔记

一、今日学习目标 1.指令补充 指令修饰符v-bind对样式增强的操作v-model应用于其他表单元素 2.computed计算属性 基础语法计算属性vs方法计算属性的完整写法成绩案例 3.watch侦听器 基础写法完整写法 4.综合案例 &#xff08;演示&#xff09; 渲染 / 删除 / 修改数量 …

创建桌面快捷方式

①点击桌面任务栏中的【开始图标】>点击【所有应用】 ②将【EndNote】图标拖到电脑桌面。

Defog发布Llama-3-SQLCoder-8B,文本转SQL模型,性能比肩GPT-4,准确率超90%,消费级硬件可运行

前言 在计算语言学领域&#xff0c;将自然语言转化为可执行的SQL查询是一个重要的研究方向。这对于让那些没有编程或SQL语法知识的用户也能轻松访问数据库信息至关重要。Defog团队近日发布了基于Llama-3的SQLCoder-8B模型&#xff0c;它在文本转SQL模型领域取得了显著突破&…

【LLM多模态】LLava模型结构和训练过程 | CLIP模型

note CLIP使用了对比学习的方法&#xff0c;即通过正样本&#xff08;匹配的图像-文本对&#xff09;和负样本&#xff08;不匹配的图像-文本对&#xff09;来训练模型。在训练过程中&#xff0c;模型会尝试最大化正样本对的相似度&#xff08;比如通过计算余弦相似度&#xf…

单细胞分析(Signac): PBMC scATAC-seq 聚类

引言 在本教学指南中&#xff0c;我们将探讨由10x Genomics公司提供的人类外周血单核细胞&#xff08;PBMCs&#xff09;的单细胞ATAC-seq数据集。 加载包 首先加载 Signac、Seurat 和我们将用于分析人类数据的其他一些包。 if (!requireNamespace("EnsDb.Hsapiens.v75&qu…

HTTP3

HTTP 状态码&#xff1a;描述了这次HTTP请求是否成功&#xff0c;以及失败的原因。 他们用相应的状态码来描述异常的发现。 常见的状态码 1.200 OK 访问成功。 2.404 NOT Found 客户端请求的资源在服务器这边不存在 URL&#xff1a;ip端口路径查询字符串 3.403 Forbid…

SQL刷题笔记day1

1题目 我的代码&#xff1a; select * from employees order by hire_date desc limit 2,1 标准代码&#xff1a; select * from employees where hire_date (select distinct hire_date from employees order by hire_date desc limit 2,1) 复盘&#xff1a;因为按照入…

vue3插槽solt 使用

背景增加组件的复用性&#xff0c;个人体验组件化还是react 方便。 Vue插槽solt如何传递具名插槽的数据给子组件&#xff1f; 一、solt 原理 知其然知其所以然 Vue的插槽&#xff08;slots&#xff09;是一种分发内容的机制&#xff0c;允许你在组件模板中定义可插入的内容…

ARP基本原理

相关概念 ARP报文 ARP报文分为ARP请求报文和ARP应答报文&#xff0c;报文格式如图1所示。 图1 ARP报文格式 Ethernet Address of destination&#xff08;0–31&#xff09;和Ethernet Address of destination&#xff08;32–47&#xff09;分别表示Ethernet Address of dest…

Mendix 版本 10.10 发布 – 跨平台的功能

​本月&#xff0c;我们将发布遍布整个平台的许多功能&#xff0c;以改善所有用户的生活。Studio Pro 包含多项生活质量改进&#xff0c;例如性能和 Epics/Jira 集成&#xff01;除此之外&#xff0c;还有一些不错的小部件、MxConnect和AI更新。以及App Insights, Mendix Cloud…

2024年5月19日优雅草蜻蜓K知识付费系统旗舰版v1.0.9进度更新

v1.1.0更新 v1.1.0更新 2024年5月19日优雅草蜻蜓K知识付费系统旗舰版v1.0.9进度更新&#xff0c;首页体育栏目完善新增用户发布页面 开发进度 首页体育栏目完善 新增用户发布页面 新增用户登录完善 新增学习课程页面完善-过往课程数据完成 去掉其他三方登录&#xff0c;新增…

文件的读写

文件操作&#xff1a; 1.打开文件 2.读/写-----操作文件 test.c------写&#xff08;输出&#xff09;------->文件 test.c<------读&#xff08;输入&#xff09;--------文件 文件名&#xff1a;文件路径文件名主干文件后缀 文件指针&#xff1a;FILE* pf;//文件指…

2024年5月24日 十二生肖 今日运势

小运播报&#xff1a;2024年5月24日&#xff0c;星期五&#xff0c;农历四月十七 &#xff08;甲辰年己巳月戊子日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;龙、牛、猴 需要注意&#xff1a;兔、羊、马 喜神方位&#xff1a;东南方 财神方位&#xff1a;…

在windows中使用wsl下的unbuntu环境

1 unbuntu下载编译环境 编译环境安装命令&#xff1a; sudo apt install gdb sudo apt install gcc sudo apt install g 2 使用vscode正常打开项目&#xff0c;在window中打开的项目&#xff08;官方推荐将项目放在linux中的home目录&#xff09; 但在windows中也可以使用&a…

数据结构---树,二叉树的简单概念介绍、堆和堆排序

树 树的概念和结构 结构 在我们将堆之前&#xff0c;我们先来了解一下我们的树。 我们的堆是属于树里面的一种&#xff0c; 树是一种非线性结构&#xff0c;是一种一对多的一种结构&#xff0c;也就是我们的一个节点可能有多个后继节点&#xff0c;当然也可以只有一个或者没…

Mac安装配置maven

文章目录 前言一、Maven介绍二、下载三、安装四、配置环境变量五、验证六、maven配置配置本地仓库配置远程仓库 七、maven的常用命令总结 前言 Maven是一个项目管理和构建自动化工具&#xff0c;主要服务于基于Java的软件项目。是我们WEB开发过程中必不可少的工具。 一、Maven…

支持北斗卫星授时的工厂NTP电子钟,打造智能化工厂时间环境

在当今数字化、智能化的工业时代&#xff0c;时间的精准性和同步性对于工厂的高效运转至关重要。支持北斗卫星授时的工厂 NTP 电子钟的出现&#xff0c;为打造智能化工厂时间环境提供了有力支撑。 一、应用原因 工厂是一个复杂且高度协作的生产环境&#xff0c;精确一致的时间是…

linux 错误记录(三)

这里的内核源码路径&#xff1a; cd /usr/src/linux-headers-5.4.0-150-generic/ 内核版本&#xff1a; $ uname -r 5.4.0-150-generic 错误现象 ./include/uapi/asm-generic/int-ll64.h:12:10: fatal error: asm/bitsperlong.h: No such file or directory 搜索后是有的 …

深度学习之基于Tensorflow图像分类模型生成与读取

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 图像分类是计算机视觉领域的重要任务之一&#xff0c;也是深度学习技术的一个核心应用。通过构…

数据库操作(函数)

函数是一段可以直接被另外一段程序调用的程序或代码 一。字符串函数 1.concat(s1,s1....sn)&#xff1a;字符串拼接&#xff0c;将s1&#xff0c;s2&#xff0c;sn拼接为一个字符串 例如&#xff1a; select concat("hello","world"); 2.lower(str&…