软件设计模式系列之二十一——观察者模式

news2024/11/26 7:41:37

1 观察者模式的定义

观察者模式(Observer Pattern)是一种行为型设计模式,它允许对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这个模式也被称为发布-订阅模式,因为它模拟了一个主题(发布者)与多个观察者(订阅者)之间的关系。

观察者模式主要用于实现对象之间的解耦,使得被观察者(主题)和观察者之间的交互更加灵活。它是一种广泛应用于软件开发中的设计模式,常见于图形界面开发、事件处理系统和分布式系统中。

2 举例说明

为了更好地理解观察者模式,让我们考虑一个实际的例子:天气站。假设我们有一个天气站应用程序,用户可以订阅该应用程序以获取实时天气更新。在这个场景中,天气站就是被观察者(主题),而订阅天气更新的用户就是观察者(订阅者)。
在这里插入图片描述

当天气站收到新的天气数据时,它会通知所有订阅者,以便它们可以更新显示当前天气的界面。这种方式使得用户可以实时获取最新的天气信息,而无需反复查询。

3 结构

观察者模式的结构包括以下几个要素:
在这里插入图片描述

Subject(主题):主题是被观察的对象,它维护一组观察者,提供方法来添加和删除观察者,并在状态发生变化时通知观察者。
ConcreteSubject(具体主题):具体主题是主题的具体实现,它包含了真正的状态和状态变化逻辑。
Observer(观察者):观察者是订阅主题的对象,它定义了一个更新接口,以便主题在状态变化时通知观察者。
ConcreteObserver(具体观察者):具体观察者是观察者的具体实现,它实现了更新接口,以便在接收到通知时执行相应的操作。

4 实现步骤

观察者模式的实现步骤如下:

创建主题接口(Subject),定义添加、删除和通知观察者的方法。
创建具体主题类(ConcreteSubject),实现主题接口,并维护观察者列表和状态变量。
创建观察者接口(Observer),定义更新方法。
创建具体观察者类(ConcreteObserver),实现观察者接口,并定义具体的更新逻辑。
在客户端中创建主题对象和观察者对象,将观察者注册到主题上。
当主题的状态发生变化时,调用主题的通知方法,通知所有注册的观察者。
观察者接收到通知后,执行相应的更新操作。

5 代码实现(Java)

让我们通过一个简单的 Java 代码示例来演示观察者模式的实现。

// Step 1: 创建主题接口
interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// Step 2: 创建具体主题类
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String weatherData;

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weatherData);
        }
    }

    public void setWeatherData(String data) {
        this.weatherData = data;
        notifyObservers();
    }
}

// Step 3: 创建观察者接口
interface Observer {
    void update(String data);
}

// Step 4: 创建具体观察者类
class User implements Observer {
    private String name;

    public User(String name) {
        this.name = name;
    }

    @Override
    public void update(String data) {
        System.out.println(name + " 收到天气更新:" + data);
    }
}

// Step 5: 客户端代码
public class Main {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();

        User user1 = new User("Alice");
        User user2 = new User("Bob");

        weatherStation.addObserver(user1);
        weatherStation.addObserver(user2);

        weatherStation.setWeatherData("晴天");
        weatherStation.setWeatherData("下雨");
    }
}

在上面的示例中,WeatherStation 是具体主题,User 是具体观察者。当天气发生变化时,WeatherStation 通知所有注册的观察者,观察者执行相应的更新操作。

6 典型应用场景

观察者模式在许多应用场景中都得到了广泛的应用,包括以下一些场景:

股票市场:投资者可以订阅股票价格的变化。一旦股票价格发生变化,所有订阅了该股票的投资者都会立即收到通知,以便他们可以做出及时的投资决策。
在这里插入图片描述

社交媒体:社交媒体平台中,用户可以关注其他用户的动态。当被关注用户发布新的动态、照片或视频时,关注者会收到通知,以便互动和评论。

库存管理:在库存管理系统中,订阅者可以订阅特定商品的库存变化。当库存数量发生变化时,订阅者可以收到通知,帮助他们及时补充库存或采取其他措施。

观察者模式将主题和观察者解耦,使主题可以轻松通知多个观察者,而观察者可以根据自己的需求选择订阅感兴趣的主题。这种模式提高了系统的灵活性和可扩展性,使信息传递更加高效和及时

7 优缺点

观察者模式的优点包括:

解耦性:被观察者和观察者之间的关系是松散耦合的,可以独立地改变它们中的任何一个,而不会影响其他部分。
可扩展性:可以轻松地添加新的观察者,扩展系统功能。
通知机制:观察者能够实时获取到被观察者的状态变化,无需主动轮询。
可维护性:代码易于维护和理解,因为逻辑分散在各个观察者中。

观察者模式的缺点包括:

如果观察者过多,通知所有观察者可能会导致性能问题。
如果观察者之间有依赖关系,可能会引入复杂性。
如果不正确地实现,可能会导致循环引用。

8 类似模式

观察者模式建立了一种一对多的依赖关系,其中一个对象(被观察者)维护一组依赖它的对象(观察者),并在状态变化时通知观察者。与观察者模式类似的模式有以下几种,它们在某些方面具有相似性,但也存在一些区别:

委托模式(Delegate Pattern):

委托模式也允许一个对象委托给多个对象,类似于观察者模式中的通知多个观察者。 在委托模式中,被委托的对象通常不知道委托它的对象,而观察者模式中,被观察者知道它的观察者并主动通知它们。委托模式通常用于事件处理和回调机制,而观察者模式用于状态变化通知。

策略模式(Strategy Pattern):

策略模式和观察者模式都关注对象之间的交互,但在策略模式中,可以根据需要切换不同的算法或行为,而观察者模式关注对象状态的变化通知。观察者模式通常用于对象之间的一对多关系,而策略模式用于定义一组可互换的算法,客户端可以在运行时选择其中一个算法。

命令模式(Command Pattern):

命令模式和观察者模式都涉及到将请求发送给接收者对象,但观察者模式关注状态变化的通知,而命令模式关注封装请求成对象。在观察者模式中,被观察者通知观察者状态的改变,而在命令模式中,客户端创建命令对象并将其发送给接收者,接收者执行命令。

这些模式都有共同点,即它们都有助于降低对象之间的耦合度,并提供了一种松散的交互方式。然而,它们的重点和用途有所不同,因此在设计应用程序时,需要根据具体需求选择最合适的模式。

9 小结

观察者模式是一种有用的设计模式,它可以帮助我们实现对象之间的松散耦合,使系统更加灵活和可扩展。通过定义一对多的依赖关系,观察者模式允许被观察者在状态变化时通知所有观察者,实现了一种高效的通知机制。在实际应用中,观察者模式可以用于各种领域,包括图形界面开发、事件处理系统、消息队列和实时数据更新等。要成功使用观察者模式,需要谨慎设计接口和类,并确保正确地管理观察者的注册和通知。

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

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

相关文章

Android stdio的Gradle菜单栏无内容问题的解决方法

右边Gradle菜单栏里没有Tasks选项内容的问题 正常情况↓ 如果这个问题如果无法解决的话&#xff0c;Gradle打包就只能通过控制台输入命令来解决&#xff0c;但这无疑是把简单问题复杂化了&#xff0c;我们来看看怎么解决这个问题吧。 这里有几个方法提供&#xff0c;可以自行选…

Ipa Guard软件介绍:启动界面和功能模块全解析,保护你的iOS应用源码

ipaguard界面概览 ipaguard界面分左右2块&#xff1a;左边菜单导航栏&#xff0c;右边的功能区 左侧菜单&#xff1a;按模块分成启动界面&#xff0c;代码模块&#xff0c;文件模块&#xff0c;重签名与测试模块 右侧主功能区会随着功能变化&#xff0c;但是整体分3块&#xf…

Webpack 基础入门以及接入 CSS、Typescript、Babel

一、什么是 Webpack Webpack 是一款 JS 模块化开发的技术框架&#xff0c;其运作原理是将多个 JS 文件关联起来构成可运行的应用程序。 Webpack 拥有丰富的 plugins / loaders 插件生态圈&#xff0c;可以让 js 识别不同的语言如 .css, .scss, .sass, .json, .xml, .ts, .vue…

揭秘:机构招生电子传单制作的五个黄金法则

机构招生微传单制作一直都是让很多人在意的事情。一款好的微传单不仅可以吸引更多的学生&#xff0c;还可以省去很多招生工作的时间和精力。但是&#xff0c;很多人却不知道如何制作一款精美的微传单。下面就让我们来学习一下如何制作一款机构招生的微传单吧。 首先&#xff0c…

聊聊Go与依赖注入

如果你读过Robert C. Martin[1]的《敏捷软件开发&#xff1a;原则、模式与实践》[2](书的封皮见下图)&#xff0c;那么你一定知道经典的SOLID设计原则[3]中的“D”&#xff1a;依赖倒置原则&#xff08;Dependency Inversion Principle, DIP&#xff09;。 依赖倒置原则是面向对…

node版本问题:Error: error:0308010C:digital envelope routines::unsupported

前言 出现这个错误是因为 node.js V17及以后版本中最近发布的OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制&#xff0c;可能会对生态系统造成一些影响. 在node.js V17以前一些可以正常运行的的应用程序,但是在 V17 及以后版本可能会抛出以下异常: 我重装系…

华为云云耀云服务器L实例评测|部署在线图表和流程图绘制工具drawio

华为云云耀云服务器L实例评测&#xff5c;部署在线图表和流程图绘制工具drawio 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 优势及其应用场景1.3 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 drawio3.1 drawio 介绍3.2 Docker 环…

宝贝详情页制作的7个步骤,一看就懂

对于许多淘宝卖家来说&#xff0c;制作精美的详情页是吸引客户和提升销售的关键。然而&#xff0c;很多卖家可能会因为缺乏设计技能和经验而感到困惑。本文将为您揭示如何使用免费在线海报制作工具&#xff0c;如乔拓云&#xff0c;来制作具有吸引力的详情页&#xff0c;让您在…

基本数据类型在内存中存储形式

目录 内存分区模型 常量 与 变量 常量的定义 #define 与 const 区别 宏与const使用 修改const常量 整数类型 无符号整数 有符号整数 补码 内存分析 浮点数类型 float类型的IEEE编码 double类型的IEEE编码 基本的浮点数指令 数据类型转换分析 浮点数作为返回值…

嵌入式Linux应用开发-基础知识-第十六章GPIO和Pinctrl子系统的使用

嵌入式Linux应用开发-基础知识-第十六章GPIO和Pinctrl子系统的使用 第十六章 GPIO 和 Pinctrl 子系统的使用16.1 Pinctrl 子系统重要概念16.1.1 引入16.1.2 重要概念16.1.3 示例16.1.4 代码中怎么引用pinctrl 16.2 GPIO子系统重要概念16.2.1 引入16.2.2 在设备树中指定引脚16.2…

React 入门笔记

前言 国庆值班把假期拆了个稀碎, 正好不用去看人潮人海, 趁机会赶个晚集入门一下都火这么久的 React 前端技术. 话说其实 n 年前也了解过一丢丢来着, 当时看到一上来就用 JS 写 DOM 的套路直接就给吓退了, 扭头还去看 Vue 了&#x1f923;, 现在从市场份额来看, 确实 React 还…

分析各种表达式求值过程

目录 算术运算与赋值 编译器常用的两种优化方案 常量传播 常量折叠 加法 Debug编译选项组下编译后的汇编代码分析 Release开启02执行效率优先 减法 Release版下优化和加法一致&#xff0c;不再赘述 乘法 除法 算术结果溢出 自增和自减 关系运算与逻辑运算 JCC指…

决胜未来:解锁新科技趋势的无尽可能性

随着科技的飞速发展,我们的未来迈入一个新的时代。无论是人工智能、区块链、大数据、物联网还是机器学习等,这些技术正以前所未有的速度重塑我们的世界和生活。面对这些未来的科技趋势,我们能否抓住其中的机遇并寻找新的突破? 首先&#xff0c;我们来看一看人工智能。人工智能…

2023年中国工业脱水机行业供需分析:随着自动化和智能化技术的快速发展,销量同比增长4.9%[图]

工业脱水机行业是指专门从湿润的固体物料中去除水分的设备制造和相关服务。它广泛应用于食品加工、化工、制药、纺织、环保等行业&#xff0c;用于去除物料中的水分&#xff0c;提高产品质量和降低能耗。 工业脱水机行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研…

基于SpringBoot的师生共评的作业管理系统设计与实现

目录 前言 一、技术栈 二、系统功能介绍 课程管理 作业管理 作业互评 小组管理 作业管理 作业评分 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个…

【Window10 】删除‘设备和驱动器’中的百度网盘、酷狗音乐、迅雷下载等

原因&#xff1a; 不想在设备里看到它。 解决方案&#xff1a; 打开cmd找到 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\ 目录在 NameSpace 目录下找到对应的软件目录&#xff0c;删除即可&#xff08;挨个目录的点击进去看…

Java / MybatisPlus:JSON处理器的应用,在实体对象中设置对象属性,对象嵌套对象

1、数据库设计 2、定义内部的实体类 /*** Author lgz* Description* Date 2023/9/30.*/ Data // 静态构造staticName&#xff0c;方便构造对象并赋予属性 AllArgsConstructor(staticName "of") NoArgsConstructor ApiModel(value "亲友", description …

web:[极客大挑战 2019]PHP

题目 点进页面显示如下 根据页面提示&#xff0c;这个网站有备份文件&#xff0c;备份文件一般是bak文件格式&#xff0c;用dirsearch扫描 访问之后下载了一个文件 里面都是一些代码 在index.php中发现了一个类的文件&#xff0c;一个get传参&#xff0c;然后将传进的值进行反序…

【强化学习】基础概念

1. Agent (智能体) 智能体是进行决策和学习的实体&#xff0c;它能感知环境的状态&#xff0c;并基于策略采取动作以影响环境。智能体的目标是通过与环境的交互获得最大化的累积奖励。 2. Environment (环境) 环境是智能体所处的外部系统&#xff0c;它与智能体交互。环境的…

Error: node: unknown or unsupported macOS version: :dunno 错误解决

一、原因 今天安装 brew install node报错了&#xff0c;错误信息如下&#xff1a; 二、解决方案 1&#xff09;查找homebrew-cask安装位置 echo $(brew --repo homebrew/homebrew-cask) // 输出 /opt/homebrew/Library/Taps/homebrew/homebrew-cask2&#xff09;使用 gi…