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

news2024/9/21 3:17:44

文章目录

    • 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应用、实时数据更新、发布-订阅系统等场景中得到了广泛应用,是软件设计中的重要模式之一。

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nginx - Stream 日志模块不完全指北

文章目录 Pre官网Nginx Stream模块基础功能Nginx Stream访问日志的缺陷解决方案或替代方案安装和配置nginx-log-enhancement模块1. 下载nginx-log-enhancement模块源代码2. 解压源代码3. 配置Nginx源代码4. 编译和安装Nginx5. 配置nginx-log-enhancement模块6. 重启Nginx7. 测试…

I/O '24|学习资源焕新,技术灵感升级

2024 年 5 月 15 日凌晨举行的 Google I/O 大会为各地的开发者们带来了新的灵感。面对技术革新&#xff0c;相信各位开发者们都迫不及待想要自己上手试一试。 别急&#xff0c;Google 谷歌今年为中国的开发者们准备了一份特别的学习资源&#xff0c;让开发者们自由探索新知。 G…

RedisTemplate操作Redis, 看这一篇文章就够了

文章目录 1. String 命令1.1 添加缓存1.2 设置过期时间(单独设置)1.3 获取缓存值1.4 删除key1.5 顺序递增1.6 顺序递减1.7 常用的 2. Hash命令2.1 添加缓存2.2 设置过期时间(单独设置)2.3 添加一个Map集合2.4 提取所有的小key2.5 提取所有的value值2.6 根据key提取value值2.7 获…

【VTKExamples::Texture】第六期 TextureThreshold

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例TextureThreshold,并解析接口vtkTexture,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~Y…

20240524每日后端---------聊聊编写简历

简历 简历就是你的名片。 生活中很多朋友却不拿简历当一回事。 最近看了几十份应聘简历&#xff0c;我不得不佩服有些老哥&#xff0c;工作十来年&#xff0c;简历还是表格的格式&#xff0c;不仅看着不好看&#xff0c;而且排版还贼差。 第一感官就很差好吧。。。 好的简历 …

二叉树(详解)

在了解二叉树之前呢我们先来了解一下树形结构&#xff0c;因为二叉树就是树形结构的一种特殊情况&#xff0c;它有这非常好的性质&#xff0c;是很常用的一种结构。 目录 一.什么是树形结构&#xff1f; 二.树形结构常见的名词 三.树的存储 四.二叉树 1.二叉树的概念 2.…

python web自动化(Pytest实战)

1.UnitTest框架与Pytest框架对⽐ 1&#xff09; unittest框架介绍 Unittest则是Python语⾔的标准单元测试框架。 Unittest⽀持⾃动化测试&#xff0c;测试⽤例的初 始化、关闭和测试⽤例的聚合等功能&#xff0c;它有⼀个很重要的特性&#xff…

勒索病毒的策略与建议

随着网络技术的快速发展&#xff0c;勒索病毒攻击成为全球范围内日益严重的网络安全威胁。勒索病毒通过加密用户文件或锁定系统来勒索赎金&#xff0c;给个人和企业带来了巨大的损失。因此&#xff0c;了解如何应对勒索病毒攻击至关重要。本文将概述一些有效的防范措施和应对策…

深入Django项目实战与最佳实践

title: 深入Django项目实战与最佳实践 date: 2024/5/19 21:41:38 updated: 2024/5/19 21:41:38 categories: 后端开发 tags: Django 基础项目实战最佳实践数据库配置静态文件部署高级特性 第一章&#xff1a;Django项目架构与设计原则 Django框架概述 Django是一个高级的P…

目前流行的前端框架有哪些?

目前流行的前端框架有很多&#xff0c;它们可以帮助开发者快速构建高质量的前端应用程序。本文将介绍一些目前比较受欢迎的前端框架&#xff0c;并分析它们的优缺点。 React React 是一个由 Facebook 开发的开源前端JavaScript库&#xff0c;用于构建用户界面&#xff0c;尤其…

如何从Android恢复已删除的文件?3 种有效的方式

有时我们可能会错误地删除Android设备上的重要文件。更疯狂的是&#xff0c;Android手机上的文件在一夜之间消失了&#xff0c;我们不知道为什么。我们感到非常遗憾和恼火&#xff0c;但不知道。但是&#xff0c;此时学习如何从Android手机恢复已删除的文件为时已晚&#xff0c…

二.常见算法--贪心算法

&#xff08;1&#xff09;单源点最短路径问题 问题描述&#xff1a; 给定一个图&#xff0c;任取其中一个节点为固定的起点&#xff0c;求从起点到任意节点的最短路径距离。 例如&#xff1a; 思路与关键点&#xff1a; 以下代码中涉及到宏INT_MAX,存在于<limits.h>中…

怎么压缩pdf pdf在线压缩 pdf文件压缩大小

pdf文件无论在何种设备上打开&#xff0c;PDF文件都能保持其原始的布局和格式&#xff0c;这对于文档共享和打印非常重要。PDF不仅支持文本&#xff0c;还能嵌入图像、视频、音频以及动态链接等元素。PDF文件支持加密和密码保护&#xff0c;可以限制访问、编辑、复制或打印文档…

Dalle2学习

Dalle2 mini有GitHub库并且有网页可以直接测试

[图解]产品经理创新模式03封装领域逻辑

1 00:00:02,530 --> 00:00:06,840 第三个改进模式就是封装领域逻辑 2 00:00:06,840 --> 00:00:12,860 把人脑里面的封装的逻辑提炼出来 3 00:00:12,870 --> 00:00:13,740 放到电脑里面去 4 00:00:16,100 --> 00:00:21,440 比如说&#xff0c;销售员的&#xff0…

Zookeeper 安装教程和使用指南

一、Zookeeper介绍 ZooKeeper 是 Apache 软件基金会的一个开源项目&#xff0c;主要基于 Java 语言实现。 Apache ZooKeeper 是一个开源的分布式应用程序协调服务&#xff0c;提供可靠的数据管理通知、数据同步、命名服务、分布式配置服务、分布式协调等服务。 关键特性 分布…

《王者荣耀》4月狂揽2.34亿美元 单日流水1亿美元 全球销量第二

易采游戏网5月24日消息&#xff0c;在刚刚过去的四月&#xff0c;全球手游市场迎来了一场收益的盛宴&#xff0c;其中《王者荣耀》以其惊人的吸金能力&#xff0c;以2.34亿美元的月收入在全球手游排行榜上位列第二。4月5日&#xff0c;这款由腾讯游戏开发的多人在线战斗竞技游戏…

JS、Go、Rust 错误处理的不同 - JS 可以不用 Try/Catch 吗?

原文&#xff1a;Mateusz Piorowski - 2023.07.24 先来了解一下我的背景吧。我是一名软件开发人员&#xff0c;有大约十年的工作经验&#xff0c;最初使用 PHP&#xff0c;后来逐渐转向 JavaScript。 大约五年前&#xff0c;我开始使用 TypeScript&#xff0c;从那时起&#…

10、SpringBoot 源码分析 - 自动配置深度分析三

SpringBoot 源码分析 - 自动配置深度分析三 refresh和自动配置大致流程AutoConfigurationImportSelector的getAutoConfigurationEntry获取自动配置实体(重点)AutoConfigurationImportSelector的getCandidateConfigurations获取EnableAutoConfiguration类型的名字集合AutoConfig…

一个超级简单的Python UI库:NiceGUI

大家好&#xff0c;图形用户界面&#xff08;GUI&#xff09;的开发往往被看作是一项复杂且繁琐的任务。Python作为一门强大的编程语言&#xff0c;提供了许多优秀的库来帮助开发者实现这一目标。今天&#xff0c;我们将介绍一个名为NiceGUI的库&#xff0c;它能帮助你轻松构建…