突破编程_C++_设计模式(责任链模式)
1 责任链模式的概念
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许对象以链式的方式组织起来,以便对请求进行处理。这种模式为多个对象处理同一请求提供了一个灵活的机制,而无需在发送者和多个请求处理者之间显式地指定耦合关系。
在责任链模式中,每个处理者对象都包含对下一个处理者的引用,从而形成了一个处理者链。当一个请求到达某个处理者时,该处理者会先判断自己是否能处理该请求。如果能处理,则直接处理;如果不能处理,则将该请求传递给链中的下一个处理者。这样,请求会沿着链一直传递,直到被某个处理者处理为止。
在 C++ 中,责任链模式通常包含以下几个关键部分:
(1)抽象处理者(Handler):
- 定义了一个处理请求的接口,通常包含一个方法用于处理请求,并持有对下一个处理者的引用。
- 抽象处理者可以是一个基类或接口,具体处理者将继承或实现这个基类或接口。
(2)具体处理者(Concrete Handler):
- 继承或实现抽象处理者,并实现了处理请求的具体逻辑。
- 具体处理者可以包含对下一个处理者的引用,以便在无法处理请求时将其传递给下一个处理者。
- 具体处理者也可以包含一个条件判断,以确定是否应该处理请求或将其传递给下一个处理者。
(3)客户端(Client):
- 创建处理者链,并将请求发送给链中的第一个处理者。
- 客户端不需要知道链中具体的处理者数量或类型,只需将请求发送给链的起点即可。
2 责任链模式的实现步骤
在 C++ 实现责任链模式的实现步骤如下:
(1)定义抽象处理者接口:
- 创建一个抽象类(或接口),定义处理请求的方法,通常命名为 HandleRequest 或类似名称。
- 在这个抽象类中,包含一个指向下一个处理者的指针或引用,用于构建处理者链。
(2)实现具体处理者类:
- 创建继承自抽象处理者接口的具体处理者类。
- 在具体处理者类中,实现 HandleRequest 方法,根据业务逻辑判断是否处理请求。
- 如果当前处理者能够处理请求,则处理并结束流程;如果不能处理,则调用下一个处理者的 HandleRequest 方法。
- 在每个具体处理者类中,包含对下一个处理者的引用,并在构造函数或设置方法中设置它。
(3)构建处理者链:
- 在客户端代码中,创建具体处理者对象,并按照需要的顺序将它们连接起来。
- 每个处理者都需要知道它之后的下一个处理者,可以通过设置方法(如 SetNext)来实现。
(4)发送请求:
- 在客户端中,通过调用链中第一个处理者的 HandleRequest 方法来发送请求。
- 请求将沿着处理者链传递,直到某个处理者处理了请求,或者请求到达了链的末尾而未被处理。
(5)处理异常情况:
- 在实现责任链模式时,需要考虑异常情况的处理。
- 如果请求在链中未被任何处理者处理,可以设计兜底逻辑,例如一个默认的处理者或者返回错误信息。
如下为样例代码:
#include <iostream>
#include <memory> // 抽象处理者
class Handler {
public:virtual ~Handler() {}virtual void HandleRequest(int request) = 0;virtual void SetNext(std::unique_ptr<Handler> next) = 0;protected:std::unique_ptr<Handler> next;
};// 具体处理者A
class ConcreteHandlerA : public Handler {
public:void SetNext(std::unique_ptr<Handler> next) override {this->next = std::move(next);}void HandleRequest(int request) override {if (request >= 0 && request < 10) {std::cout << "ConcreteHandlerA handled request " << request << std::endl;}else if (next) {next->HandleRequest(request);}else {std::cout << "No handler could process request " << request << std::endl;}}
};// 具体处理者B
class ConcreteHandlerB : public Handler {
public:void SetNext(std::unique_ptr<Handler> next) override {this->next = std::move(next);}void HandleRequest(int request) override {if (request >= 10 && request < 20) {std::cout << "ConcreteHandlerB handled request " << request << std::endl;}else if (next) {next->HandleRequest(request);}else {std::cout << "No handler could process request " << request << std::endl;}}
};// 客户端代码
int main()
{// 创建处理者对象并使用智能指针管理 std::unique_ptr<Handler> handlerA = std::make_unique<ConcreteHandlerA>();std::unique_ptr<Handler> handlerB = std::make_unique<ConcreteHandlerB>();// 构建处理者链 handlerA->SetNext(std::move(handlerB));// 发送请求给链的第一个处理者 handlerA->HandleRequest(5); // 由ConcreteHandlerA处理 handlerA->HandleRequest(15); // 由ConcreteHandlerB处理 handlerA->HandleRequest(25); // 无人处理,输出错误信息 return 0;
}
上面代码的输出为:
ConcreteHandlerA handled request 5
ConcreteHandlerB handled request 15
No handler could process request 25
这个样例使用了 std::unique_ptr 来管理处理者对象的生命周期,确保在链中传递时不会发生内存泄漏。每个具体处理者(ConcreteHandlerA 和 ConcreteHandlerB)都实现了 HandleRequest 方法来处理请求,并通过调用 SetNext 方法来设置下一个处理者。如果当前处理者不能处理请求,它将请求传递给链中的下一个处理者。如果在链的末尾仍然没有处理者能够处理请求,则输出一个错误信息。
注意:在 main 函数中,使用 std::make_unique 来创建具体处理者的实例,并使用 std::move 来将智能指针的所有权从一个对象传递到另一个对象,从而构建处理者链。这样做可以确保在链中正确地管理对象的生命周期,并避免不必要的拷贝操作。
3 责任链模式的应用场景
C++责任链模式的应用场景主要集中在需要多个对象处理同一请求,且具体处理对象在运行时动态决定的场合。以下是一些具体的应用场景:
(1)业务流程处理: 如采购审批流程、请假流程等,这些流程可能涉及多个部门和人员,每个部门和人员都有自己的处理逻辑和权限。使用责任链模式可以方便地实现这些流程的自动化处理。
(2)多个对象处理同一请求: 当系统中有多个对象都可以处理某一类请求,但具体由哪个对象处理需要在运行时决定时,可以使用责任链模式。例如,在一个复杂的业务逻辑中,可能有多个处理者需要根据不同的条件来处理同一请求。
(3)请求处理者不明确: 在不明确指定接收者的情况下,可以向多个对象中的一个提交请求。责任链模式允许请求在多个处理者之间传递,直到有处理者能够处理该请求为止。这种模式在处理异常、事件或消息传递时特别有用。
(4)动态指定处理者: 需要动态地指定一组对象来处理请求时,也可以使用责任链模式。例如,在某些情况下,处理者的数量或顺序可能会根据系统的运行状态或配置而发生变化。
3.1 责任链模式应用于业务流程处理
下面是一个 C++ 中使用智能指针和责任链模式应用于业务流程处理的示例。在这个例子中,假设有一个请假审批流程,它包含多个审批环节,如部门主管审批、人事审批等。每个审批环节都是一个处理者,它们按照顺序组成责任链。
首先,定义抽象处理者接口和具体处理者类:
#include <iostream>
#include <memory>
#include <string> // 抽象处理者
class LeaveApprovalHandler {
public:virtual ~LeaveApprovalHandler() {}virtual void HandleRequest(const std::string& employee, int days) = 0;virtual void SetNext(std::unique_ptr<LeaveApprovalHandler> next) = 0;protected:std::unique_ptr<LeaveApprovalHandler> next;
};// 具体处理者:部门主管审批
class DepartmentHeadHandler : public LeaveApprovalHandler {
public:void SetNext(std::unique_ptr<LeaveApprovalHandler> next) override {this->next = std::move(next);}void HandleRequest(const std::string& employee, int days) override {if (days <= 3) {std::cout << "Department Head approved leave for " << employee << " for " << days << " days." << std::endl;}else {if (next) {next->HandleRequest(employee, days);}else {std::cout << "No further approval handler available for " << employee << " for " << days << " days." << std::endl;}}}
};// 具体处理者:人事审批
class HRHandler : public LeaveApprovalHandler {
public:void SetNext(std::unique_ptr<LeaveApprovalHandler> next) override {this->next = std::move(next);}void HandleRequest(const std::string& employee, int days) override {if (days > 3 && days <= 7) {std::cout << "HR approved leave for " << employee << " for " << days << " days." << std::endl;}else if (next) {next->HandleRequest(employee, days);}else {std::cout << "No further approval handler available for " << employee << " for " << days << " days." << std::endl;}}
};// 最终处理者:总经理审批
class GeneralManagerHandler : public LeaveApprovalHandler {
public:void HandleRequest(const std::string& employee, int days) override {if (days > 7) {std::cout << "General Manager approved leave for " << employee << " for " << days << " days." << std::endl;}else {std::cout << "Leave request for " << employee << " for " << days << " days was not approved by General Manager." << std::endl;}}void SetNext(std::unique_ptr<LeaveApprovalHandler> /*next*/) override {// 最终处理者后面没有其他处理者 }
};
接下来,在客户端代码中构建责任链,并发送请求:
int main()
{// 创建具体处理者对象并使用智能指针管理 std::unique_ptr<LeaveApprovalHandler> departmentHead = std::make_unique<DepartmentHeadHandler>();std::unique_ptr<LeaveApprovalHandler> hr = std::make_unique<HRHandler>();std::unique_ptr<LeaveApprovalHandler> generalManager = std::make_unique<GeneralManagerHandler>();// 构建处理者链 hr->SetNext(std::move(generalManager));departmentHead->SetNext(std::move(hr));// 发送请假请求给链的第一个处理者 departmentHead->HandleRequest("Alice", 2); // 部门主管审批 departmentHead->HandleRequest("Bob", 5); // 人事审批 departmentHead->HandleRequest("Charlie", 10); // 总经理审批 return 0;
}
上面代码的输出为:
Department Head approved leave for Alice for 2 days.
HR approved leave for Bob for 5 days.
General Manager approved leave for Charlie for 10 days.
在这个示例中,LeaveApprovalHandler 是抽象处理者接口,DepartmentHeadHandler、HRHandler 和 GeneralManagerHandler 是具体处理者类,它们分别代表了不同层级的审批者。每个处理者都实现了 HandleRequest 方法来处理请求,并通过 SetNext 方法将请求传递给链中的下一个处理者。
运行这个程序,可以看到根据员工请假的天数,不同的处理者会处理或传递请求。如果请求到达链的末尾仍未被处理,则输出相应的消息。
3.2 责任链模式应用于多个对象处理同一请求
在C++中,责任链模式用于多个对象处理同一请求的场景时,通常每个对象都表示链中的一个节点,负责处理请求或将其传递给链中的下一个节点。下面是一个构建和处理责任链的示例:
首先,定义处理请求的抽象接口和具体处理者类:
#include <iostream>
#include <memory>
#include <string> // 抽象请求处理者
class Handler {
public:virtual ~Handler() {}// 处理请求 virtual void HandleRequest(int type, const std::string& request) = 0;// 设置下一个处理者 virtual void SetNext(std::unique_ptr<Handler> next) = 0;protected:std::unique_ptr<Handler> next;
};// 具体的请求处理者A
class HandlerA : public Handler {
public:void HandleRequest(int type, const std::string& request) override {if (0 == type) {std::cout << "HandlerA processing request: " << request << std::endl;}else {if (next) {next->HandleRequest(type,request);}else {std::cout << "Request not processed: " << request << std::endl;}}}void SetNext(std::unique_ptr<Handler> next) override {this->next = std::move(next);}
};// 具体的请求处理者B
class HandlerB : public Handler {
public:void HandleRequest(int type, const std::string& request) override {if (1 == type) {std::cout << "HandlerB processing request: " << request << std::endl;}else {if (next) {next->HandleRequest(type, request);}else {std::cout << "Request not processed: " << request << std::endl;}}}void SetNext(std::unique_ptr<Handler> next) override {this->next = std::move(next);}
};// 终端处理者(没有下一个处理者)
class HandlerTerminal : public Handler {
public:void HandleRequest(int type, const std::string& request) override {std::cout << "HandlerTerminal processing request: " << request << std::endl;}void SetNext(std::unique_ptr<Handler> /*next*/) override {// 终端处理者不需要设置下一个处理者 }
};
然后,在客户端代码中,可以创建处理者对象并使用智能指针来构建责任链:
int main()
{// 创建处理者对象 std::unique_ptr<Handler> handlerA = std::make_unique<HandlerA>();std::unique_ptr<Handler> handlerB = std::make_unique<HandlerB>();std::unique_ptr<Handler> handlerTerminal = std::make_unique<HandlerTerminal>();// 构建责任链 handlerB->SetNext(std::move(handlerTerminal));handlerA->SetNext(std::move(handlerB));// 发送请求 handlerA->HandleRequest(0, "Request 1");handlerA->HandleRequest(1, "Request 2");handlerA->HandleRequest(2, "Request 3");return 0;
}
上面代码的输出为:
HandlerA processing request: Request 1
HandlerB processing request: Request 2
HandlerTerminal processing request: Request 3
在这个例子中,Handler 是一个抽象接口,HandlerA 和 HandlerB 是实现了这个接口的具体类,它们根据某些条件来决定是否处理请求,或者将请求传递给链中的下一个处理者。HandlerTerminal 是一个终端处理者,它没有下一个处理者,并且总是处理传递给它的请求。
每个处理者内部都持有一个指向下一个处理者的 std::unique_ptr 智能指针。当处理者决定不处理请求时,它会调用 next->HandleRequest(request) 来将请求传递给链中的下一个处理者。如果当前处理者是链中的最后一个(即 next 为空),则输出一条消息表示请求未被处理。
4 责任链模式的优点与缺点
C++ 责任链模式的优点主要包括:
(1)耦合度降低: 通过将请求的处理分散到多个处理者对象中,责任链模式降低了客户端与具体处理者之间的耦合度。客户端只需要将请求发送给链中的第一个处理者,而不需要知道链的具体结构或每个处理者的具体实现。
(2)扩展性好: 如果需要添加新的处理逻辑,只需要创建新的处理者类并将其添加到链中即可,无需修改已有的代码。这使得系统的扩展变得非常容易和灵活。
(3)动态性增强: 处理者对象之间的顺序可以在运行时动态调整,根据业务逻辑的需要,可以方便地改变请求的处理流程。
(4)支持多重处理: 一个请求可以依次被多个处理者处理,每个处理者都可以对请求进行部分处理或添加额外的信息,然后将请求传递给下一个处理者。
然而,C++ 责任链模式也存在一些缺点:
(1)性能开销: 由于请求需要在链中依次传递,如果链很长或者处理者的处理逻辑复杂,可能会导致性能下降。特别是在处理大量请求时,这种开销可能会变得显著。
(2)调试困难: 由于请求在链中传递,当出现问题时,定位问题可能会比较困难。需要逐个检查每个处理者以找出问题所在。
(3)链的配置和管理: 构建和维护责任链可能需要额外的代码和逻辑来管理处理者之间的依赖关系和顺序。这可能会增加代码的复杂性和维护成本。
(4)可能导致请求被忽略: 如果没有正确处理链的终止条件或没有设置终端处理者,请求可能会在链中丢失或被忽略,导致业务逻辑不完整或错误。
相关文章:
突破编程_C++_设计模式(责任链模式)
1 责任链模式的概念 责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许对象以链式的方式组织起来,以便对请求进行处理。这种模式为多个对象处理同一请求提供了一个灵活的机制,而无需在发送者和多…...
php开发100问?
什么是 PHP?PHP 是一种什么类型的语言?PHP 的优缺点是什么?如何在服务器上配置 PHP?PHP 中的变量是如何声明和使用的?如何在 PHP 中输出文本和变量?什么是 PHP 的数据类型?如何在 PHP 中实现条件…...

flink实战--Flink任务资源自动化优化
背景 在生产环境Flink任务资源是用户在实时平台端进行配置,用户本身对于实时任务具体配置多少资源经验较少,所以存在用户资源配置较多,但实际使用不到的情形。比如一个 Flink 任务实际上 4 个并发能够满足业务处理需求,结果用户配置了 16 个并发,这种情况会导致实时计算资…...
tsv文件在大数据技术栈里的应用场景
是的,\t 是指制表符(tab),它通常用作字段分隔符在 TSV(Tab-Separated Values)格式的文件中。TSV是一种简单的文本格式,它使用制表符来分隔每一列中的值,而每一行则代表一个数据记录。…...

vscode设置setting.json
{ // vscode默认启用了根据文件类型自动设置tabsize的选项 "editor.detectIndentation": false, // 重新设定tabsize "editor.tabSize": 2, // #每次保存的时候自动格式化 // "editor.formatOnSave": true, // #每次保存的时候将代码按eslint格式…...

Docker的安装及镜像加速的配置
文章目录 一.切换到root二.卸载旧版docker三.配置docker的yum库四.安装Docker五.Docker的启动和验证六.配置Docker阿里云镜像加速(全程免费) 该文章文章演示在Linux系统中安装docker,Windows安装docker请参考以下文章 Windows系统中安装docker及镜像加速的配置 一…...
AIGC时代IT人的迷茫有解(1):从“商业画布”到“个人画布”
IT人的迷茫和心态调整 最近打开新闻,各种IT老大都在说“AIGC时代,只要会说话,人人都会具备程序员的能力”,身边也有很多程序员朋友也已经在用GPT类的产品编程了。随着AIGC的发展,除了程序员,可能很多职业都会被替代或…...

Qt/QML编程之路:openglwidget和倒车影像的切换(43)
关于如何实现一个基于OpenGL的3d 图形,这个有很多专门的介绍,我在开发中遇到了这么一个问题: 如何实现一个倒车影像的video显示与一个3D物体显示的切换,因为开窗在同样的一个位置,如果车子倒车启动,则需要将原本显示3D的地方切换为视频图像的显示。 class testOpenGl : …...
Spring 初学者遇到的问题
TagLibraryValidator Spring 实战 5.2 中有个表单需要在 jsp 中遍历数组,添加:<% taglib uri"http://java.sun.com/jsp/jstl/core" prefix"c" %>,访问时发现有些问题: java.lang.NoClassDefFoundError…...

前端解决跨域问题( 6种方法 )
本专栏是汇集了一些HTML常常被遗忘的知识,这里算是温故而知新,往往这些零碎的知识点,在你开发中能起到炸惊效果。我们每个人都没有过目不忘,过久不忘的本事,就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…...

Linux 理解进程
目录 一、基本概念 二、描述进程-PCB 1、task_struct-PCB的一种 2、task_ struct内容分类 三、组织进程 四、查看进程 1、ps指令 2、top命令 3、/proc文件系统 4、在/proc文件中查看指定进程 5、进程的工作目录 五、通过系统调用获取进程标示符 1、getpid()/get…...

鸿蒙App基础
基础说明 .1、应用模型 .1.1、构成要素 应用组件 应用组件是应用的基本组成单位,是应用的运行入口。用户启动、使用和退出应用过程中,应用组件会在不同的状态间切换,这些状态称为应用组件的生命周期。应用组件提供生命周期的回调函数&…...
算法部署优化工程师面试题整理
🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:C/C面试整理 🎀CSDN主页 发狂的小花 🌄人生秘诀:学习的本质就是极致重复! 目录 整体情况简介 高性能计算基础 AI 框架知识 算…...

C#,入门教程(26)——数据的基本概念与使用方法
上一篇: C#,入门教程(25)——注释(Comments)你会吗?看多图演示,学真正注释。https://blog.csdn.net/beijinghorn/article/details/124681888 本文所述的知识基本上适用于C/C,java等其他语言。 …...

加密与安全_PGP、OpenPGP和GPG加密通信协议
文章目录 PGPOpenPGPGPG工作原理工作流程用途案例说明过程 代码实现pom依赖PgpEncryptionUtilPgpDecryptionUtilCommonUtilsPgpEncryptionTest 小结 PGP PGP (Pretty Good Privacy) 是一种加密通信协议,用于保护电子邮件和文件的安全性和隐私。它通过使用加密、数字…...
Maven模块化最佳实践
一,模块化的原因及意义 模块化是一种将大型的软件系统拆分成相互独立的模块的方法。具有以下优势: 代码复用:不同的模块可以共享相同的代码。这样可以避免重复编写相同的代码,提高开发效率。 模块独立性:每个模块都可…...

嵌入式C语言中 #pragma once 的作用
1、#pragma once有什么作用? 为了避免同一个头文件被包含(include)多次,C/C中有两种宏实现方式: 一种是#ifndef方式; 另一种是#pragma once方式。 在能够支持这两种方式的编译器上,二者并没…...

spring-cloud-openfeign 3.0.0(对应spring boot 2.4.x之前版本)之前版本feign整合ribbon请求流程
在之前写的文章配置基础上 https://blog.csdn.net/zlpzlpzyd/article/details/136060312 下图为自己整理的...

#数据结构 线性表的顺序存储
目录 每日文案 一、线性表的定义 二、线性表的操作 顺序表的存储结构 顺序表的初始化操作 判断顺序表是否为空表 将顺序表置为空表 计算顺序表中的元素个数 取出顺序表中的对应位置元素 取出对应数值的位序 在对应位置插入元素 将对应位置的元素删除 将顺序表中的数据…...

[iOS]高版本MacOS运行低版本Xcode
Xcode 版本支持文档 目的: 在MacOS Sonoma 系统上安装 Xcode14.3.1 第一步 先在Xcode下载一个Xcode14.3.1的压缩包 第二步 本地解压Xcode,将外层目录名变更为Xcode_14.3.1,将文件拷贝到 /Applications目录下。 第三步 变更xcode-sel…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...