【Rust】——面向对象设计模式的实现

 🎼个人主页:【Y小夜】

😎作者简介:一位双非学校的大二学生,编程爱好者,

专注于基础和实战分享,欢迎私信咨询!

🎆入门专栏:🎇【MySQL,Java基础,Rust】

🎈热门专栏:🎊【Python,Javaweb,Vue框架】

感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️

学习推荐:

    人工智能是一个涉及数学、计算机科学、数据科学、机器学习、神经网络等多个领域的交叉学科,其学习曲线相对陡峭,对初学者来说可能会有一定的挑战性。幸运的是,随着互联网教育资源的丰富,现在有大量优秀的在线平台和网站提供了丰富的人工智能学习材料,包括视频教程、互动课程、实战项目等,这些资源无疑为学习者打开了一扇通往人工智能世界的大门。

        前些天发现了一个巨牛的人工智能学习网站:前言 – 人工智能教程通俗易懂,风趣幽默,忍不住分享一下给大家。

目录

🎯定义Post并新建一个草案状态的实例

🎯存放博文内容的文本

🎯确保博文草案的内容是空的

🎯请求审核博文来改变其状态

🎯增加改变content行为的approve方法

🎯状态模式的权衡取舍

🎯将状态和行为编码为类型

🎯实现状态转移为不同类型的转换


        状态模式state pattern)是一个面向对象设计模式。该模式的关键在于定义一系列值的内含状态。这些状态体现为一系列的 状态对象,同时值的行为随着其内部状态而改变。我们将编写一个博客发布结构体的例子,它拥有一个包含其状态的字段,这是一个有着 "draft"、"review" 或 "published" 的状态对象

        状态对象共享功能:当然,在 Rust 中使用结构体和 trait 而不是对象和继承。每一个状态对象负责其自身的行为,以及该状态何时应当转移至另一个状态。持有一个状态对象的值对于不同状态的行为以及何时状态转移毫不知情。

        使用状态模式的优点在于,程序的业务需求改变时,无需改变值持有状态或者使用值的代码。我们只需更新某个状态对象中的代码来改变其规则,或者是增加更多的状态对象。

        首先我们将以一种更加传统的面向对象的方式实现状态模式,接着使用一种更 Rust 一点的方式。让我们使用状态模式增量式地实现一个发布博文的工作流以探索这个概念。

这个博客的最终功能看起来像这样:

  1. 博文从空白的草案开始。
  2. 一旦草案完成,请求审核博文。
  3. 一旦博文过审,它将被发表。
  4. 只有被发表的博文的内容会被打印,这样就不会意外打印出没有被审核的博文的文本。

        任何其他对博文的修改尝试都是没有作用的。例如,如果尝试在请求审核之前通过一个草案博文,博文应该保持未发布的状态。

        这是一个我们将要在一个叫做 blog 的库 crate 中实现的 API 的示例。这段代码还不能编译,因为还未实现 blog

use blog::Post;fn main() {let mut post = Post::new();post.add_text("I ate a salad for lunch today");assert_eq!("", post.content());post.request_review();assert_eq!("", post.content());post.approve();assert_eq!("I ate a salad for lunch today", post.content());
}

        我们希望允许用户使用 Post::new 创建一个新的博文草案。也希望能在草案阶段为博文编写一些文本。如果在审批之前尝试立刻获取博文的内容,不应该获取到任何文本因为博文仍然是草案。一个好的单元测试将是断言草案博文的 content 方法返回空字符串,不过我们并不准备为这个例子编写单元测试。

        接下来,我们希望能够请求审核博文,而在等待审核的阶段 content 应该仍然返回空字符串。最后当博文审核通过,它应该被发表,这意味着当调用 content 时博文的文本将被返回。

        注意我们与 crate 交互的唯一的类型是 Post。这个类型会使用状态模式并会存放处于三种博文所可能的状态之一的值 —— 草案,等待审核和发布。状态上的改变由 Post 类型内部进行管理。状态依库用户对 Post 实例调用的方法而改变,但是不能直接管理状态变化。这也意味着用户不会在状态上犯错,比如在过审前发布博文。

🎯定义Post并新建一个草案状态的实例

        让我们开始实现这个库吧!我们知道需要一个公有 Post 结构体来存放一些文本,所以让我们从结构体的定义和一个创建 Post 实例的公有关联函数 new 开始,

   Post 将在私有字段 state 中存放一个 Option<T> 类型的 trait 对象 Box<dyn State>。稍后将会看到为何 Option<T> 是必须的。

pub struct Post {state: Option<Box<dyn State>>,content: String,
}impl Post {pub fn new() -> Post {Post {state: Some(Box::new(Draft {})),content: String::new(),}}
}trait State {}struct Draft {}impl State for Draft {}

   State trait 定义了所有不同状态的博文所共享的行为,这个状态对象是 DraftPendingReview 和 Published,它们都会实现 State 状态。现在这个 trait 并没有任何方法,同时开始将只定义 Draft 状态因为这是我们希望博文的初始状态。

        当创建新的 Post 时,我们将其 state 字段设置为一个存放了 Box 的 Some 值。这个 Box 指向一个 Draft 结构体新实例。这确保了无论何时新建一个 Post 实例,它都会从草案开始。因为 Post 的 state 字段是私有的,也就无法创建任何其他状态的 Post 了!。Post::new 函数中将 content 设置为新建的空 String

🎯存放博文内容的文本

展示了我们希望能够调用一个叫做 add_text 的方法并向其传递一个 &str 来将文本增加到博文的内容中。选择实现为一个方法而不是将 content 字段暴露为 pub 。这意味着之后可以实现一个方法来控制 content 字段如何被读取。

impl Post {// --snip--pub fn add_text(&mut self, text: &str) {self.content.push_str(text);}
}

  add_text 获取一个 self 的可变引用,因为需要改变调用 add_text 的 Post 实例。接着调用 content 中的 String 的 push_str 并传递 text 参数来保存到 content 中。这不是状态模式的一部分,因为它的行为并不依赖博文所处的状态。add_text 方法完全不与 state 状态交互,不过这是我们希望支持的行为的一部分。

🎯确保博文草案的内容是空的

        即使调用 add_text 并向博文增加一些内容之后,我们仍然希望 content 方法返回一个空字符串 slice,因为博文仍然处于草案状态,如示例 17-11 的第 8 行所示。现在让我们使用能满足要求的最简单的方式来实现 content 方法:总是返回一个空字符串 slice。当实现了将博文状态改为发布的能力之后将改变这一做法。但是目前博文只能是草案状态,这意味着其内容应该总是空的。

impl Post {// --snip--pub fn content(&self) -> &str {""}
}

🎯请求审核博文来改变其状态

        接下来需要增加请求审核博文的功能,这应当将其状态由 Draft 改为 PendingReview

impl Post {// --snip--pub fn request_review(&mut self) {if let Some(s) = self.state.take() {self.state = Some(s.request_review())}}
}trait State {fn request_review(self: Box<Self>) -> Box<dyn State>;
}struct Draft {}impl State for Draft {fn request_review(self: Box<Self>) -> Box<dyn State> {Box::new(PendingReview {})}
}struct PendingReview {}impl State for PendingReview {fn request_review(self: Box<Self>) -> Box<dyn State> {self}
}

        这里为 Post 增加一个获取 self 可变引用的公有方法 request_review。接着在 Post 的当前状态下调用内部的 request_review 方法,并且第二个 request_review 方法会消费当前的状态并返回一个新状态。

        这里给 State trait 增加了 request_review 方法;所有实现了这个 trait 的类型现在都需要实现 request_review 方法。注意不同于使用 self、 &self 或者 &mut self 作为方法的第一个参数,这里使用了 self: Box<Self>。这个语法意味着该方法只可在持有这个类型的 Box 上被调用。这个语法获取了 Box<Self> 的所有权使老状态无效化,以便 Post 的状态值可转换为一个新状态。

        为了消费老状态,request_review 方法需要获取状态值的所有权。这就是 Post 的 state 字段中 Option 的来历:调用 take 方法将 state 字段中的 Some 值取出并留下一个 None,因为 Rust 不允许结构体实例中存在值为空的字段。这使得我们将 state 的值移出 Post 而不是借用它。接着我们将博文的 state 值设置为这个操作的结果。

        我们需要将 state 临时设置为 None 来获取 state 值,即老状态的所有权,而不是使用 self.state = self.state.request_review(); 这样的代码直接更新状态值。这确保了当 Post 被转换为新状态后不能再使用老 state 值。

   Draft 的 request_review 方法需要返回一个新的,装箱的 PendingReview 结构体的实例,其用来代表博文处于等待审核状态。结构体 PendingReview 同样也实现了 request_review 方法,不过它不进行任何状态转换。相反它返回自身,因为当我们请求审核一个已经处于 PendingReview 状态的博文,它应该继续保持 PendingReview 状态。

🎯增加改变content行为的approve方法

approve 方法将与 request_review 方法类似:它会将 state 设置为审核通过时应处于的状态

impl Post {// --snip--pub fn approve(&mut self) {if let Some(s) = self.state.take() {self.state = Some(s.approve())}}
}trait State {fn request_review(self: Box<Self>) -> Box<dyn State>;fn approve(self: Box<Self>) -> Box<dyn State>;
}struct Draft {}impl State for Draft {// --snip--fn approve(self: Box<Self>) -> Box<dyn State> {self}
}struct PendingReview {}impl State for PendingReview {// --snip--fn approve(self: Box<Self>) -> Box<dyn State> {Box::new(Published {})}
}struct Published {}impl State for Published {fn request_review(self: Box<Self>) -> Box<dyn State> {self}fn approve(self: Box<Self>) -> Box<dyn State> {self}
}

        这里为 State trait 增加了 approve 方法,并新增了一个实现了 State 的结构体,Published 状态。

        类似于 PendingReview 中 request_review 的工作方式,如果对 Draft 调用 approve 方法,并没有任何效果,因为它会返回 self。当对 PendingReview 调用 approve 时,它返回一个新的、装箱的 Published 结构体的实例。Published 结构体实现了 State trait,同时对于 request_review 和 approve 两方法来说,它返回自身,因为在这两种情况博文应该保持 Published 状态。

impl Post {// --snip--pub fn content(&self) -> &str {self.state.as_ref().unwrap().content(self)}// --snip--
}

        因为目标是将所有像这样的规则保持在实现了 State 的结构体中,我们将调用 state 中的值的 content 方法并传递博文实例(也就是 self)作为参数。接着返回 state 值的 content 方法的返回值。

        这里调用 Option 的 as_ref 方法是因为需要 Option 中值的引用而不是获取其所有权。因为 state 是一个 Option<Box<dyn State>>,调用 as_ref 会返回一个 Option<&Box<dyn State>>。如果不调用 as_ref,将会得到一个错误,因为不能将 state 移动出借用的 &self 函数参数。

        接着我们就有了一个 &Box<dyn State>,当调用其 content 时,Deref 强制转换会作用于 & 和 Box ,这样最终会调用实现了 State trait 的类型的 content 方法。

trait State {// --snip--fn content<'a>(&self, post: &'a Post) -> &'a str {""}
}// --snip--
struct Published {}impl State for Published {// --snip--fn content<'a>(&self, post: &'a Post) -> &'a str {&post.content}
}

        这里增加了一个 content 方法的默认实现来返回一个空字符串 slice。这意味着无需为 Draft 和 PendingReview 结构体实现 content 了。Published 结构体会覆盖 content 方法并会返回 post.content 的值。

🎯状态模式的权衡取舍

        我们展示了 Rust 是能够实现面向对象的状态模式的,以便能根据博文所处的状态来封装不同类型的行为。Post 的方法并不知道这些不同类型的行为。通过这种组织代码的方式,要找到所有已发布博文的不同行为只需查看一处代码:Published 的 State trait 的实现。

        如果要创建一个不使用状态模式的替代实现,则可能会在 Post 的方法中,或者甚至于在 main 代码中用到 match 语句,来检查博文状态并在这里改变其行为。这意味着需要查看很多位置来理解处于发布状态的博文的所有逻辑!这在增加更多状态时会变得更糟:每一个 match 语句都会需要另一个分支。

        对于状态模式来说,Post 的方法和使用 Post 的位置无需 match 语句,同时增加新状态只涉及到增加一个新 struct 和为其实现 trait 的方法。

这个实现易于扩展增加更多功能。为了体会使用此模式维护代码的简洁性,请尝试如下一些建议:

  • 增加 reject 方法将博文的状态从 PendingReview 变回 Draft
  • 在将状态变为 Published 之前需要两次 approve 调用
  • 只允许博文处于 Draft 状态时增加文本内容。提示:让状态对象负责内容可能发生什么改变,但不负责修改 Post

        状态模式的一个缺点是因为状态实现了状态之间的转换,一些状态会相互联系。如果在 PendingReview 和 Published 之间增加另一个状态,比如 Scheduled,则不得不修改 PendingReview 中的代码来转移到 Scheduled。如果 PendingReview 无需因为新增的状态而改变就更好了,不过这意味着切换到另一种设计模式。

        另一个缺点是我们会发现一些重复的逻辑。为了消除它们,可以尝试为 State trait 中返回 self 的 request_review 和 approve 方法增加默认实现,不过这会违反对象安全性,因为 trait 不知道 self 具体是什么。我们希望能够将 State 作为一个 trait 对象,所以需要其方法是对象安全的。

        另一个重复是 Post 中 request_review 和 approve 这两个类似的实现。它们都委托调用了 state 字段中 Option 值的同一方法,并在结果中为 state 字段设置了新值。如果 Post 中的很多方法都遵循这个模式,我们可能会考虑定义一个宏来消除重复(查看第十九章的 “宏” 部分)。

        完全按照面向对象语言的定义实现这个模式并没有尽可能地利用 Rust 的优势。让我们看看一些代码中可以做出的修改,来将无效的状态和状态转移变为编译时错误。

🎯将状态和行为编码为类型

        我们将展示如何稍微反思状态模式来进行一系列不同的权衡取舍。不同于完全封装状态和状态转移使得外部代码对其毫不知情,我们将状态编码进不同的类型。如此,Rust 的类型检查就会将任何在只能使用发布博文的地方使用草案博文的尝试变为编译时错误。

fn main() {let mut post = Post::new();post.add_text("I ate a salad for lunch today");assert_eq!("", post.content());
}

        我们仍然希望能够使用 Post::new 创建一个新的草案博文,并能够增加博文的内容。不过不同于存在一个草案博文时返回空字符串的 content 方法,我们将使草案博文完全没有 content 方法。这样如果尝试获取草案博文的内容,将会得到一个方法不存在的编译错误。这使得我们不可能在生产环境意外显示出草案博文的内容,因为这样的代码甚至就不能编译。

pub struct Post {content: String,
}pub struct DraftPost {content: String,
}impl Post {pub fn new() -> DraftPost {DraftPost {content: String::new(),}}pub fn content(&self) -> &str {&self.content}
}impl DraftPost {pub fn add_text(&mut self, text: &str) {self.content.push_str(text);}
}

  Post 和 DraftPost 结构体都有一个私有的 content 字段来储存博文的文本。这些结构体不再有 state 字段因为我们将状态编码改为结构体类型。Post 将代表发布的博文,它有一个返回 content 的 content 方法。

        仍然有一个 Post::new 函数,不过不同于返回 Post 实例,它返回 DraftPost 的实例。现在不可能创建一个 Post 实例,因为 content 是私有的同时没有任何函数返回 Post

🎯实现状态转移为不同类型的转换

        那么如何得到发布的博文呢?我们希望强制执行的规则是草案博文在可以发布之前必须被审核通过。等待审核状态的博文应该仍然不会显示任何内容。让我们通过增加另一个结构体 PendingReviewPost 来实现这个限制,在 DraftPost 上定义 request_review 方法来返回 PendingReviewPost,并在 PendingReviewPost 上定义 approve 方法来返回 Post

impl DraftPost {// --snip--pub fn request_review(self) -> PendingReviewPost {PendingReviewPost {content: self.content,}}
}pub struct PendingReviewPost {content: String,
}impl PendingReviewPost {pub fn approve(self) -> Post {Post {content: self.content,}}
}

  request_review 和 approve 方法获取 self 的所有权,因此会消费 DraftPost 和 PendingReviewPost 实例,并分别转换为 PendingReviewPost 和发布的 Post。这样在调用 request_review 之后就不会遗留任何 DraftPost 实例,后者同理。PendingReviewPost 并没有定义 content 方法,所以尝试读取其内容会导致编译错误,DraftPost 同理。因为唯一得到定义了 content 方法的 Post 实例的途径是调用 PendingReviewPost 的 approve 方法,而得到 PendingReviewPost 的唯一办法是调用 DraftPost 的 request_review 方法,现在我们就将发博文的工作流编码进了类型系统。

        这也意味着不得不对 main 做出一些小的修改。因为 request_review 和 approve 返回新实例而不是修改被调用的结构体,所以我们需要增加更多的 let post = 覆盖赋值来保存返回的实例。也不再能断言草案和等待审核的博文的内容为空字符串了,我们也不再需要它们:不能编译尝试使用这些状态下博文内容的代码。

use blog::Post;fn main() {let mut post = Post::new();post.add_text("I ate a salad for lunch today");let post = post.request_review();let post = post.approve();assert_eq!("I ate a salad for lunch today", post.content());
}

        不得不修改 main 来重新赋值 post 使得这个实现不再完全遵守面向对象的状态模式:状态间的转换不再完全封装在 Post 实现中。然而,得益于类型系统和编译时类型检查,我们得到了的是无效状态是不可能的!这确保了某些特定的 bug,比如显示未发布博文的内容,将在部署到生产环境之前被发现。

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

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

相关文章

张量之力:人工智能的多维舞台

在人工智能&#xff08;AI&#xff09;的广阔天地里&#xff0c;张量&#xff08;Tensor&#xff09;这一数学概念如同璀璨的明星&#xff0c;以其独特的魅力和强大的功能&#xff0c;为AI技术的发展和应用注入了新的活力。张量&#xff0c;这个源自物理学的概念&#xff0c;如…

通州公司代理记账,以专业服务提升企业运营效率

我们为您提供“通州公司代理记账”的全面信息&#xff0c;作为一家专业的代理记账机构&#xff0c;我们的目标是为您的企业提供最优质的服务&#xff0c;帮助您更高效地管理财务。 代理记账是一项重要的商业活动&#xff0c;它不仅可以帮助企业节约时间和成本&#xff0c;而且…

boot整合solr

换了新项目组&#xff0c;技术相对老些&#xff0c;于是用boot框架简单记录下&#xff01; 安装 下载路径&#xff1a;https://solr.apache.org/downloads.html Windows环境 下载solr-8.2.0.zip包并解压缩&#xff0c;以管理员身份打开cmd&#xff0c;执行 solr cmd 命令启…

负反馈放大电路

开环放大倍数&#xff1a;放大电路没有加反馈时的放大倍数A 闭环放大倍数&#xff1a;电路加了反馈信号的放大倍数Af。反馈信号和输出信号的比值称为反馈系数F。 三极管各极电压变化关系 1&#xff0c;三极管的基极和发射极之间是同相关系&#xff0c;当基极电压上升&#x…

【Java】单例设计模式

单例设计模式简介 目录 1.单例设计模式是什么&#xff1f;2.单例设计模式设计方法饿汉式懒汉式 3.单例设计模式的应用任务管理器(仅有一个页面&#xff0c;不可多开)Runtime运行环境 1.单例设计模式是什么&#xff1f; 设计模式 是解决 特定问题的优秀设计方式之一。 单例设计…

怎么把m4a转换成mp3?四种常见的转换方法介绍!

怎么把m4a转换成mp3&#xff1f;在处理m4a音频文件时&#xff0c;我们可能会遇到一系列复杂的问题&#xff0c;首先&#xff0c;考虑到m4a是一种相对较新的音频格式&#xff0c;老旧的设备或软件可能无法准确识别它&#xff0c;这可能导致用户无法在这些设备上播放或编辑m4a文件…

西门子学习笔记10 - MCGS和西门子1200进行通讯设置

1、博图软件的设置 1、修改PLC的ip地址为192.168.1.1 2、打开put&#xff0c;get通讯功能 3、设置通讯变量&#xff0c;可以是M区也可以是DB块的数据 2、MCGSE组态环境设置 1、新建项目&#xff0c;在设备窗口界面进入设备窗口 2、添加设备如下 3、双击进入配置界面 4、添加变…

[线程与网络] 网络编程与通信原理(六):深入理解应用层http与https协议(网络编程与通信原理完结)

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

[职场] 美术学就业方向和前景 #经验分享#学习方法

美术学就业方向和前景 2011年国务院学位委员会、教育部颁布了新的《学位授予和人才培养学科目录》&#xff0c;艺术学首次从文学门类中独立出来&#xff0c;成为新的第13个学科门类&#xff0c;即艺术学门类。其中&#xff0c;美术学又是艺术学门类下的五个一级学科之一。但是…

亿发软件:信息化与数字化,相互交织的科技双引擎

在现代科技发展的浪潮中&#xff0c;信息化和数字化是两个频繁被提及的关键词。尽管它们在很多情况下被视为同义词&#xff0c;但其实两者有着本质的区别和相互影响的关系。究竟是信息化推动了数字化&#xff0c;还是数字化引领了信息化的进程&#xff1f;本文将深入探讨信息化…

数字驱动:企业发展的火箭助推器!

​ 在这个数字经济时代&#xff0c;数据就像火箭燃料&#xff0c;而数字驱动则是那强大的火箭助推器&#xff01;它正以惊人的力量助力企业飞速发展&#xff01; 数字驱动&#xff0c;助力企业发展的超强引擎&#xff01; 用数据说话&#xff0c;决策不再盲目&#xff01; 以数…

Vue CLI 环境变量使用指南

一、简介 Vue CLI 是一个强大的前端工程化工具&#xff0c;它提供了丰富的配置选项&#xff0c;包括环境变量的管理。环境变量允许开发者根据不同的运行环境&#xff08;如开发、测试和生产&#xff09;应用不同的配置&#xff0c;而无需更改代码。本文将详细介绍如何在 Vue C…

redis 03 RDB AOF

1.数据库状态 2.为什么会出现RDB 3.什么是RDB 5.1 5.2 6 6.1 6.2 6.2.1 6.2.2 6.2.3 7 8. 8.1 9 9.1 9.2 9.3 9.4 9.5

心链12-----队伍页业务完善+匹配算法实现随机匹配(最短距离算法)

心链 — 伙伴匹配系统 搜索队伍 我们选择vant组件库里的基础搜索框&#xff0c;复制到TeamPage页面&#xff0c;同时还有查询为空时&#xff0c;显示的无结果页面&#xff08;用户页面以写过&#xff09; 因为&#xff0c;我们一次性挂载本质性也是搜索队伍&#xff0c;所以…

@Validated 前端表单数据校验

1. 整合 1.1 依赖引入 <dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId></dependency>1.2 控制层 /*** 新增胎架计划** param subsectionPlanVo* return*/PostMapping("/sched…

数据结构复习指导之外部排序

目录 外部排序 复习提示 1.外部排序的基本概念 2.外部排序的方法 2.1对大文件排序时使用的排序算法&#xff08;2016&#xff09; 3.多路平衡归并与败者树 4.置换-选择排序&#xff08;生成初始归并段&#xff09; 4.1置换-选择排序生成初始归并段的实例(2023) 5.最佳…

【经验】Ubuntu上离线安装VsCode插件浏览Linux kernel源码

1、下载VsCode离线安装包 1.1 下载 下载地址:https://marketplace.visualstudio.com/vscode 本人安装的插件: C/C++ checkpatch Chinese clangd kconfig Makefile Tools Perl Perl Toolbox注意:C/C++插件要安装Linux 64版本 1.2 安装 将离线安装包拷贝到Ubuntu中,执…

SpringCloud整合OpenFeign实现微服务间的通信

1. 前言 1.1 为什么要使用OpenFeign&#xff1f; 虽说RestTemplate 对HTTP封装后, 已经⽐直接使⽤HTTPClient简单⽅便很多, 但是还存在⼀些问题. 需要拼接URL, 灵活性⾼, 但是封装臃肿, URL复杂时, 容易出错. 代码可读性差, ⻛格不统⼀。 1.2 介绍一下微服务之间的通信方式 微…

使用 stress 命令进行Linux CPU 压力测试

大家好&#xff0c;在现代计算机系统中&#xff0c;对系统性能和稳定性的评估是至关重要的。特别是在服务器环境中&#xff0c;我们需要确保系统能够在高负载情况下稳定运行&#xff0c;以满足用户的需求。而 CPU 是系统中最关键的组件之一&#xff0c;其性能直接影响着整个系统…

Python 快速查找并替换Excel中的数据

Excel中的查找替换是一个非常实用的功能&#xff0c;能够帮助用户快速完成大量数据的整理和处理工作&#xff0c;避免手动逐一修改数据的麻烦&#xff0c;提高工作效率。要使用Python实现这一功能&#xff0c; 我们可以借助Spire.XLS for Python 库&#xff0c;具体操作如下&am…