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

【观察者】设计模式:构建灵活且响应式的软件系统

引言

在软件开发中,我们经常面临需要在多个对象之间进行通信的挑战。特别是当一个对象的状态发生变化时,我们希望所有依赖于这个状态的对象都能自动更新。这就是观察者设计模式大显身手的地方。

简介

观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。

核心组件

  • Subject(主题):也称为Observable,它维护一组观察者,提供添加、删除和通知观察者的接口;
  • Observer(观察者):为所有具体观察者定义一个接口,在得到主题的通知时更新自己;
  • ConcreteSubject(具体主题):保存状态,当状态变化时通知观察者;
  • ConcreteObserver(具体观察者):实现观察者更新接口,以便在主题状态变化时更新自己。

经典实现

// 主题-被观察者
public interface Subject {void registerObserver(Observer observer); //注册观察者void removeObserver(Observer observer); //移除观察者void notifyObservers(Message message); //通知观察者
}
// 观察者
public interface Observer {void update(Message message);
}public class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<Observer>();@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(Message message) {for (Observer observer : observers) {observer.update(message);}}
}//观察者1
public class ConcreteObserverOne implements Observer {@Overridepublic void update(Message message) {//TODO: 获取消息通知,执行自己的逻辑...System.out.println("ConcreteObserverOne is notified.");}
}
//观察者2
public class ConcreteObserverTwo implements Observer {@Overridepublic void update(Message message) {//TODO: 获取消息通知,执行自己的逻辑...System.out.println("ConcreteObserverTwo is notified.");}
}public class Demo {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();subject.registerObserver(new ConcreteObserverOne());subject.registerObserver(new ConcreteObserverTwo());subject.notifyObservers(new Message());}
}

投资理财系统

比如,我们现在在开发一个投资理财系统,用户注册成功后,会给用户发放投资体验金,代码实现大致如下:

public class UserController {private UserService userService; // 依赖注入private PromotionService promotionService; // 依赖注入public Long register(String telephone, String password) {// 注册long userId = userService.register(telephone, password);// 发放体验金promotionService.issueNewUserExperienceCash(userId);return userId;}
}

假如没有扩展修改的需求,那么现在的代码是可以被接受的。如果非得用观察者模式,就会引入更多的类和更加复杂的代码结构,反而是一种过度设计

相反,假如需求频繁改动,比如用户注册成功后,不再发放体验金,而是改为发放优惠券,且给用户发送一封“注册成功”的站内信。此时,就需要频繁修改register函数的代码,违反开闭原则。
而且,如果注册成功后需要执行的后续操作越来越多,那register函数也会越来越复杂,影响代码的可读性和可维护性。

同步阻塞实现

//观察者接口
public interface RegObserver {void handleRegSuccess(long userId);
}//观察者1
public class RegPromotionObserver implements RegObserver {private PromotionService promotionService; // 依赖注入@Overridepublic void handleRegSuccess(long userId) {promotionService.issueNewUserExperienceCash(userId);}
}
//观察者2
public class RegNotificationObserver implements RegObserver {private NotificationService notificationService;@Overridepublic void handleRegSuccess(long userId) {notificationService.sendInboxMessage(userId, "Welcome...");}
}public class UserController {private UserService userService; // 依赖注入private List<RegObserver> regObservers = new ArrayList<>();// 设置观察者public void setRegObservers(List<RegObserver> observers) {regObservers.addAll(observers);}public Long register(String telephone, String password) {long userId = userService.register(telephone, password);//通知观察者for (RegObserver observer : regObservers) {observer.handleRegSuccess(userId);}return userId;}
}

被观察者代码和观察者代码在同一个线程中执行,被观察者代码一直阻塞,直到所有的观察者代码都执行完毕后,才执行后续的代码。
register函数依次调用执行每个观察者的handleRegSuccess函数,都执行完成后,才会返回结果给客户端。

异步非阻塞实现

如果注册接口是一个调用非常频繁的接口,对性能非常敏感,希望接口的响应时间尽可能的短,可以将同步阻塞的实现方式改为异步非阻塞的实现方式,以此来减少响应时间。
register函数执行完成后,启动一个新的线程来执行观察者的handleRegSuccess函数。

跨进程实现

同步阻塞和异步非阻塞都是进程内的实现方式。
而基于消息队列实现的方式则属于一个跨进程的实现方式,观察者和被观察者解耦的更加彻底,两者都感知不到对方的存在。被观察者只管发送消息到消息队列,观察者只管从消息队列中读取消息来执行相应的逻辑。
在这里插入图片描述

总结

观察者模式提供了一种强大的方法来实现对象之间的松耦合通信。它允许系统在不修改现有代码的情况下,通过增加新的观察者来扩展其功能。通过使用观察者模式,我们可以构建出更加灵活、可维护和响应式的软件系统。

参考文献
《极客时间-设计模式之美》

相关文章:

【观察者】设计模式:构建灵活且响应式的软件系统

引言 在软件开发中&#xff0c;我们经常面临需要在多个对象之间进行通信的挑战。特别是当一个对象的状态发生变化时&#xff0c;我们希望所有依赖于这个状态的对象都能自动更新。这就是观察者设计模式大显身手的地方。 简介 观察者模式是一种行为设计模式&#xff0c;它定义…...

开源网安斩获CCIA中国网络安全创新创业大赛总决赛三等奖

近日&#xff0c;由中央网信办指导&#xff0c;中国网络安全产业联盟&#xff08;CCIA&#xff09;主办的2024年中国网络安全创新创业大赛总决赛及颁奖典礼在国家网络安全宣传周落下帷幕。开源网安“AI代码审核平台CodeSec V4.0” 凭借在AI方向的技术创新、技术突破及功能应用创…...

进程的同步与互斥

目录 一、进程同步 二、进程互斥 1.临界资源访问代码&#xff1a; ①进入区 ②临界区 ③退出区 ④剩余区 注&#xff1a; 2.互斥准则&#xff1a; ①.空闲让进。 ②.忙则等待。 ③.有限等待。 ④.让权等待。 三、进程互斥的软件实现方法 1.单标志法 2.双标志先…...

基础的八股

JS this 全局&#xff1a;this指向window 函数&#xff1a;this指向window 对象&#xff1a;this指向调用它的 get、post的区别 1、写的地方不同&#xff1a;get在地址栏里 地址栏有多长就只能写多少、post在请求体里 没有上限 2、关于回退和刷新&#xff1a;get回退和刷新没问…...

使用Python从头开始创建PowerPoint演示文稿

目录 一、环境搭建与基础知识 1.1 环境搭建 1.2 基础知识 二、创建演示文稿对象 三、添加幻灯片 3.1 选择幻灯片布局 3.2 设置幻灯片内容 3.2.1 设置标题和副标题 3.2.2 添加文本内容 3.2.3 插入图片 3.2.4 插入图表 四、高级应用&#xff1a;批量生成演示文稿 4.…...

【C++ Primer Plus习题】15.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "sales.h"…...

Pipeline Scheduling(UVA 690)

网址如下&#xff1a; Pipeline Scheduling - UVA 690 - Virtual Judge (vjudge.net) &#xff08;第三方网站&#xff09; 噫&#xff0c;好&#xff01;我中了&#xff01; 这题还是有点折磨的&#xff0c;刚开始我只会递归下一个程序运行的时间&#xff08;范围在1~n&…...

萤石举办2024清洁机器人新品发布会 多维智能再造行业标杆

导言&#xff1a;作为智慧生活守护者&#xff0c;萤石今日发布了两款清洁机器人&#xff0c;AI扫拖机器人RS20 Pro Ultra 和AI洗地机器人RX30 Max &#xff0c;标志着萤石在智能清洁领域的全新突破。RS20 Pro Ultra基于CutFree 2.0内切割滚刷专利&#xff0c;有效解决毛发缠绕难…...

企业级Ansible自动化运维项目案例:实战与技巧

在企业级的IT运维中&#xff0c;自动化已成为提高效率、减少人为错误和保证服务一致性的关键手段。Ansible作为一种简单但功能强大的自动化工具&#xff0c;广泛应用于配置管理、应用程序部署、任务自动化和IT编排。本文将通过一个企业级的Ansible自动化运维项目案例&#xff0…...

JavaSE-易错题集-005

1. 下面有关java object默认的基本方法&#xff0c;说法错误的是&#xff1f; A equals(Object obj) 指示某个其他对象是否与此对象“相等” B copy() 创建并返回此对象的一个副本 C wait() 导致当前的线程等待&#xff0c;直到其他线程调用此对象的 notify() 方法或 notifyA…...

决策树模型的可解释性

我们首先介绍一下一个比较简单的机器学习模型&#xff0c;其在设计之初就已经有了比较好的可 解释性&#xff0c;这个模型就是决策树模型。决策树相较于线性的模型&#xff0c;它是更强大的模型。而决策树 的另外一个好处&#xff0c;相较于深度学习它具有良好的可解释性。比如…...

2. geoserver 发布postgis数据

1. 新建工作空间 2. 新建存储空间 3. 新建图层 4. 切片图层 5. 查看发布的图层...

【渗透测试】——Brup Suite平台安装

&#x1f4d6; 前言&#xff1a;Burp Suite 是用于攻击 web 应用程序的集成平台。它包含了许多Burp工具&#xff0c;这些不同的burp工具通过协同工作&#xff0c;有效的分享信息&#xff0c;支持以某种工具中的信息为基础供另一种工具使用的方式发起攻击。 它主要用来做安全性…...

redis:全局ID生成器实现

问题&#xff1a;订单id不能设置为自增长的原因 id的规律性太明显&#xff0c; 受订单的数据量限制:若数据量过大&#xff0c;需要多张表存储&#xff0c;若自增会导致id重复 全局ID生成器&#xff1a;在分布式系统中用来生成全局唯一ID的工具 ID的组成&#xff1a; 符号位…...

jenkins工具的介绍和gitlab安装

使用方式 替代手动&#xff0c;自动化拉取、集成、构建、测试&#xff1b;是CI/CD持续集成、持续部署主流开发模式中重要工具&#xff1b;必须组件 jenkins-gitlab&#xff0c;代码公共仓库服务器&#xff08;至少6G内存&#xff09;&#xff1b;jenkins-server&#xff0c;需…...

【从0开始在CentOS 9中安装Tomcat】

从0开始在CentOS 9中安装Tomcat 1. 安装 Java&#xff08;Tomcat 需要 Java 环境&#xff09;2. 下载并安装 Tomcat3. 配置 Tomcat4. 启动 Tomcat5. 配置 Tomcat 为开机自启动6. 验证 Tomcat 运行状态7. 允许防火墙开放 8080 端口&#xff08;可选&#xff09; 要在 Linux 上安…...

学习Vue3的第五天

目录 API对比 shallowRef 与 shallowReactive 对比总结 使用场景 总结 readonly 与 shallowReadonly 对比总结 使用场景 总结 toRaw 与 markRaw 对比总结 使用场景 总结 customRef 应用场景 总结 示例&#xff1a;异步数据获取 Vue3新组件 Teleport Suspen…...

Python 类中使用 cursor.execute() 时语法错误的解决方法

在 Python 类中使用 cursor.execute() 时&#xff0c;出现语法错误&#xff08;如 SyntaxError 或 SQL 语法相关错误&#xff09;通常是因为 SQL 语句格式不正确、占位符使用不当&#xff0c;或参数传递方式不符合预期。以下是解决此类问题的常见方法和建议。 问题背景 在 Pyt…...

怎么选择靠谱AI论文生成工具?看完我的试用都会明白!

2024年上半年开始AI论文写作工具开始火了&#xff0c;层出不穷&#xff01;作为一个经常需要写论文的懒人&#xff0c;我非常好奇这些AI工具的实际效果到底怎么样&#xff1f;为了测试不同工具的实力&#xff0c;我对他们都进行了试用&#xff0c;发现了一些意想不到的结果....…...

Java 每日一刊(第3期):Hello World

文章目录 前言Hello World程序是如何执行的Hello World 里有什么本期小知识 阳光洒进窗台&#xff0c;花香伴着书香&#xff0c;静谧而温暖&#xff0c;仿佛时光停驻。 前言 这里是分享 Java 相关内容的专刊&#xff0c;每日一更。 本期将为大家带来以下内容&#xff1a; “…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...