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

让代码变美的第一天 - 观察者模式

文章目录

  • 丑陋的模样
  • 变美步骤
    • 第一步 - 基本预期
    • 第二步 - 核心逻辑梳理
    • 第三步 - 重构
      • 重构1 - 消息定义
      • 重构2 - 消息订阅
      • 重构3 - 消息发布
    • 高级用法
      • 按顺序订阅
      • 异步订阅
      • 多消息订阅

丑陋的模样

当我们开发一个功能,代码可能如下:

private void test() {func1();func2();func3();
}
  • 目前看起来还是美美哒,结构清晰,层次分明
    新需求来的时候,慢慢的变成了下面这样:
private void test() {func1();try {func2();} catch (Exception e) {}func3();func4();// func5if (1 == 1) {for (int i = 0; i < 5; i++) {// todo1// todo2}}
}
  • 多人开发的话,情况更严重。当项目大了里面的逻辑很少有人能全部讲清楚,老代码没人敢动(劝你也不要动,一年到头辛辛苦苦,背个故障从头来过)
  • 代码会越来越乱,在一个方法里面堆砌的代码会越来越多,如果有洁癖一点的可能还会把新代码封装成func4,如果偷懒可能就变成了func5()下面的代码了,屎山代码可能就是这样出来的吧

变美步骤

第一步 - 基本预期

思考:这个功能,这个方法改动到底是不是很频繁。有个预期就行,如果没有预期,那就看实际改动次数。

  • 如果不频繁,建议就这样吧,只要结构清晰,方便review代码就行。不鼓励过度设计,毕竟开发时间都是有限的。
  • 如果很频繁,就看第二步

第二步 - 核心逻辑梳理

还是上面那个代码,需要思考到底哪部分是核心,假设func1、func2、func3是库存校验、下单、修改库存。func4、func5是销量统计、发货
那么很容易判断出,func123才是核心逻辑,是下单的必要步骤。func45就是下单完之后的一些后续处理,甚至可能都不需要同步处理,比如发货,和下单并没有强绑定。
很容易就判断出来,这可能是一个发布订阅的逻辑,可以用观察者模式来重构,学了这么多年的设计模式,这不就能用上了么。

第三步 - 重构

  • 如果未来计划很明确,项目越做越大,肯定要拆分成多个微服务,组成一个分布式服务,并且已经有消息中间件了(Kafka、RocketMQ等),那么就直接上吧,用发布订阅来异步、解耦、削峰。
  • 如果还没有那么明确的目标,也不想引入大型中间件,那么重构一下代码还是很不错的。

重构1 - 消息定义

只讨论使用spring项目

public class OrderEvent {private long id;private String desc;
}
  • 需要向下传递的参数信息

重构2 - 消息订阅

@Service
public class OrderEventListenerService {@EventListenerpublic void handleForOrderSaveEvent(OrderEvent event) {log.info("收到接单消息:{}", event);}
}
  • 这里订阅的就是func4/5

重构3 - 消息发布

@Service
public class OrderEventPublishService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void order() {OrderEvent event = new OrderEvent(1, "接单");log.info("发送接单消息:{}", event);eventPublisher.publishEvent(event);log.info("消息发送完毕:{}", event);}
}
  • 这里就是func1/2/3
    三步就搞定了重构,并且下次修改,只需要新增一个订阅方法。

高级用法

按顺序订阅

func4、func5是需要有先后顺序的,那么只需要加上@Order(num),按到num从小到大的顺序先后处理

@Service
public class OrderEventListenerService {@Order(2)@EventListenerpublic void handleForOrderSaveEvent1(OrderEvent event) {log.info("2同步收到接单消息:{}", event);}@Order(1)@EventListenerpublic void handleForOrderSaveEvent2(OrderEvent event) {log.info("1同步收到接单消息:{}", event);}
}

异步订阅

如果func5是发货,完全不依赖下单,订阅方就可以异步处理,使用@Async就行了。

@Service
public class OrderEventListenerService {@Async@EventListenerpublic void asyncHandleForOrderSaveEvent(OrderEvent event) {log.info("异步收到接单消息:{}", event);}
}

注意:使用的是默认线程池,最好改成自定义的线程池

多消息订阅

如果func5是发货,除了C端用户下单以外,B端用户也能下单,但是B端下单代码完全是另一份,那么就需要有B端的下单消息,func5统一处理发货流程就行了

@Service
public class OrderEventListenerService {@Async@EventListener(classes = {OrderAEvent.class, OrderBEvent.class})public void asyncHandleForOrderSaveEvent(Object event) {log.info("异步收到接单消息:{}", event);}
}

相关文章:

让代码变美的第一天 - 观察者模式

文章目录 丑陋的模样变美步骤第一步 - 基本预期第二步 - 核心逻辑梳理第三步 - 重构重构1 - 消息定义重构2 - 消息订阅重构3 - 消息发布 高级用法按顺序订阅异步订阅多消息订阅 丑陋的模样 当我们开发一个功能&#xff0c;代码可能如下&#xff1a; private void test() {fun…...

微服务-网关设计

文章目录 引言I 网关部署java启动jar包II 其他服务部署细节2.1 服务端api 版本号III 网关常规设置3.1 外部请求系统服务都需要通过网关访问3.2 第三方平台回调校验文件的配置IV 微服务日志跟踪4.1 打印线程ID4.2 封装线程池任务执行器4.3 将自身MDC中的数据复制给子线程4.4 微服…...

WxJava使用lettuce的redis实现access_token的共享

使用WxJava微信开发时&#xff0c;调用接口获取access_token&#xff0c;如果多个服务部署&#xff0c;就需要使用到缓存来保存access_token以达到重复利用&#xff0c;WxJava 也提供了相关的实现类WxMaRedisConfigImpl&#xff0c;但是这个是基于jedis客户端的实现&#xff0c…...

干货:如何运作一个全新品牌?

新品牌推广是真金白银的事儿&#xff0c;在你不了解情况的时候&#xff0c;最好以观察为主&#xff0c;不要不管三七二十一就动手。小马识途营销顾问建议创业者首先要找到自己的细分市场&#xff0c;按如下步骤去运作一个新品牌。 第一步、社群试水 先建立一个目标受众的社群&a…...

TCP/IP卷一详解第二章Internet地址结构概要

在这一章中介绍了Internet中使用的网络层地址&#xff08;也就是IP地址&#xff09;&#xff0c;还有如何为Internet中的设备分配地址&#xff0c;以及各种类型的地址等等…… 一、IP地址的表示 为大家所常见的有IPV4地址和IPV6地址&#xff0c;但在IPV4地址中&#xff0c;通…...

小程序 打开方式 页面效果 表单页面 点击跳到详情页 图标 获取后台数据 进行页面渲染

请求地址&#xff1a;geecg-uniapp 同源策略 数据请求 获取后台数据 ui库安装 冲突解决&#xff08;3&#xff09;-CSDN博客 一.uniapp转小程序 (1) 运行微信开发工具 &#xff08;2&#xff09; 配置id 然后运行 打开小程序 路径 E:\通\uniapp-jeecg\unpackage\dist\d…...

一个“Hello, World”Flask应用程序

如果您访问Flask网站&#xff0c;会看到一个非常简单的示例应用程序&#xff0c;只有5行代码。为了不重复那个简单的示例&#xff0c;我将向您展示一个稍微复杂一些的示例&#xff0c;它将为您编写大型应用程序提供一个良好的基础结构。 应用程序将存在于包中。在Python中&…...

计算机丢失mfc100.dll如何恢复,详细解析mfc100.dll文件丢失解决方法

在计算机使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;比如“mfc100.dll丢失”。这是因为动态链接库&#xff08;DLL&#xff09;文件是Windows操作系统的重要组成部分&#xff0c;它们包含了许多程序运行所需的函数和数据。当这些DLL文件丢失或损坏时&#x…...

分享一本让你真正理解深度学习的书

关注微信公众号&#xff1a;人工智能大讲堂&#xff0c;后台回复udl获取pdf文档。 今天要分享的书是Understanding Deep Learning&#xff0c;作者是西蒙普林斯&#xff0c;英国巴斯大学的荣誉教授&#xff0c;其个人学术能力相当强大&#xff0c;在AI领域有着深厚的学术造诣。…...

Apache APISIX Dashboard 未经认证访问导致 RCE(CVE-2021-45232)漏洞复现

漏洞描述 Apache APISIX 是一个动态、实时、高性能的 API 网关&#xff0c;而 Apache APISIX Dashboard 是一个简单易用的前端界面&#xff0c;用于管理 Apache APISIX。 在 2.10.1 之前的 Apache APISIX Dashboard 中&#xff0c;Manager API 使用了两个框架&#xff0c;并在…...

Git 安全警告修复手册:解决 `fatal: detected dubious ownership in repository at ` 问题 ️

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

【MySQL事务篇】多版本并发控制(MVCC)

多版本并发控制(MVCC) 文章目录 多版本并发控制(MVCC)1. 概述2. 快照读与当前读2.1 快照读2.2 当前读 3. MVCC实现原理之ReadView3.1 ReadView概述3.2 设计思路3.3 ReadView的规则3.4 MVCC整体操作流程 4. 举例说明4.1 READ COMMITTED隔离级别下4.2 REPEATABLE READ隔离级别下 …...

拆分代码 + 动态加载 + 预加载,减少首屏资源,提升首屏性能及应用体验

github 原文地址 我们看一些针对《如何提升应用首屏加载体验》的文章&#xff0c;提到的必不可少的措施&#xff0c;便是减少首屏幕加载资源的大小&#xff0c;而减少资源大小必然会想到按需加载措施。本文提到的便是一个基于webpack 插件与 react 组件实现的一套研发高度自定…...

在 Vue3 中使用 mitt 进行组件通信

npm 包地址 mitt 是一个轻量级的 JavaScript 事件触发器&#xff0c; 只有200b。有基本的事件触发、订阅和取消订阅功能&#xff0c;还支持用命名空间来进行更高级的事件处理。 功能特点&#xff1a; Microscopic —— weighs less than 200 bytes gzippedUseful —— a wil…...

SQLite 3.44.0 发布!

SQLite 开发团队于 2023 年 11 月 01 日发布了 SQLite 3.44.0 版本&#xff0c;带来了一些 SQL 和优化器增强&#xff0c;本文给大家做一个简要分分析。 新增 concat() 函数 新版本增加了两个连接字符串的函数&#xff1a;concat() 以及 concat_ws()。它们可以兼容 PostgreSQ…...

本地生活新赛道-视频号团购怎么做?

目前有在做实体行业的商家一定要看完&#xff0c;只要你进入了这个本地生活新的赛道&#xff0c;那你的生意自然会源源不断&#xff0c;那这个赛道又是什么呢&#xff1f; 这就是十月份刚刚上线的视频号团购项目&#xff0c;开通团购之后&#xff0c;就可以通过发短视频&#…...

输入一个url后,会发生什么事?

Internet上的每一个网页都具有一个唯一的名称标识&#xff0c;通常称之为URL&#xff08;Uniform Resource Locator,统一资源定位器&#xff09;。它是www的统一资源定位标志&#xff0c;简单地说URL就是web地址&#xff0c;俗称“网址”。 所以当我们在浏览器上输入一个url后&…...

R语言和jsonlite库编写代码示例

R语言和jsonlite库来下载的程序。 r # 导入jsonlite库 library(jsonlite) # 设置代理主机和端口 proxy_host <- "" proxy_port <- # 使用httr库创建一个对象 proxy <- create_proxy(proxy_host, proxy_port) # 使用httr库的GET方法下载网页内容 url <…...

容联七陌携手岚时科技,解决医美机构回访3大痛点

近日&#xff0c;岚时科技研发中心联合容联七陌发布了全新的智能呼叫中心系统&#xff0c;5大功能模块解决了医美机构回访过程中的3大难题&#xff1a;客户资产保全困难、客户回访技术被卡脖子、回访人员&#xff08;客服、咨询&#xff09;效率管理困难。 “智能呼叫中心”通过…...

自动计算零售数据分析指标?BI软件表示可行

随着BI技术的飞速发展&#xff0c;借助系统来计算分析指标也不是什么难事&#xff0c;即便是面对组合多变的零售数据分析指标&#xff0c;奥威BI软件也依旧可以又快又精准地完成指标计算。 BI软件可以自动计算零售数据分析指标&#xff0c;如销售额、库存量、订单量等。在计算…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...