18.中介者模式:思考与解读
原文地址:中介者模式:思考与解读 更多内容请关注:深入思考与解读设计模式
引言
在软件开发中,尤其是处理多个对象交互时,你是否遇到过一个问题:当多个对象需要互相通信时,系统变得复杂,难以管理?每个对象都需要直接与其他对象进行通信,导致类之间的依赖性过强,系统的可维护性降低。那么,是否有一种方式可以将对象间的交互从每个对象中分离出来,让它们之间的依赖关系更松散?
中介者模式正是为了解决这一问题而设计的。它通过引入一个中介者对象,将多个对象的通信集中在一起,避免了对象之间直接依赖,减少了系统的复杂性。你是否理解,为什么将对象之间的直接通信集中到一个中介者中,能够简化系统的设计?
在本文中,我们将通过一系列问题,逐步引导你理解中介者模式的核心思想、应用场景以及如何实现它。
什么是中介者模式?
问题1:当多个对象需要相互通信时,通常如何管理它们的关系?你会让对象直接通信,还是考虑使用某种方式来减少它们之间的耦合?
假设你有多个对象需要相互沟通,比如在一个用户界面中,有多个组件(如按钮、文本框、标签等),它们之间需要协调工作。你是否会让每个组件直接与其他组件通信,还是通过某种中介机制来协调它们的行为?
问题2:如果对象之间不直接通信,而是通过一个中心化的中介者来管理,它是否能够简化对象之间的依赖关系,降低系统的复杂性?
中介者模式将对象的通信集中到一个中介者对象中,所有的交互都通过中介者来完成。你是否理解,为什么这种集中化的通信机制能够减少对象间的依赖,使得系统更加灵活、易于扩展?
中介者模式的核心概念
问题3:中介者模式通常包含哪些角色?每个角色的职责是什么?
中介者模式主要包含以下几个核心角色:
-
中介者(Mediator):定义一个接口,用于协调对象之间的交互。
-
具体中介者(ConcreteMediator):实现中介者接口,管理和协调各个同事对象的交互。
-
同事类(Colleague):每个同事类都有一个对中介者的引用,通过中介者与其他同事对象进行交互。
你能理解这些角色是如何协同工作的?它们如何通过将对象间的通信委托给中介者来减少直接依赖?
问题4:为什么要引入中介者对象?它如何将对象之间的通信从直接的关系中解耦?
在传统的设计中,每个对象可能直接与其他对象通信,导致对象间的紧密耦合。而中介者模式通过集中化通信,将所有的交互通过中介者来管理。你是否理解,这种设计如何减少了对象之间的直接依赖,从而提高了系统的灵活性?
问题5:通过中介者来管理对象的交互,是否意味着每次需要变更对象的交互逻辑时,都只需要修改中介者?而不需要修改其他类的代码?
当对象之间的交互逻辑发生变化时,通过中介者模式,你只需要修改中介者类,而不需要修改每个对象的实现。你是否理解,这种方式如何让系统更加易于扩展和维护?
中介者模式的实现
假设你正在开发一个简单的聊天应用,多个用户之间可以发送消息。你希望避免让每个用户直接与其他用户通信,而是通过一个中介者(即聊天服务器)来协调消息的传递。
步骤1:定义中介者接口
from abc import ABC, abstractmethod# 定义中介者接口
class ChatMediator(ABC):@abstractmethoddef send_message(self, message: str, user: 'User'):pass
问题6:为什么我们需要定义一个中介者接口(ChatMediator
)?它的作用是什么?
ChatMediator
接口定义了发送消息的方法,这个方法将由具体中介者来实现。你是否理解,为什么通过一个统一的接口来管理通信可以使得对象之间不直接依赖?
步骤2:定义同事类(用户类)
class User:def __init__(self, name: str, mediator: ChatMediator):self.name = nameself.mediator = mediatordef send(self, message: str):print(f"{self.name} sends message: {message}")self.mediator.send_message(message, self)def receive(self, message: str):print(f"{self.name} receives message: {message}")
问题7:User
类如何作为同事类与中介者进行交互?为什么每个用户都需要持有一个对中介者的引用?
每个用户类通过调用send()
方法向中介者发送消息,同时也可以通过receive()
方法接收消息。你是否理解,为什么通过中介者来传递消息,让用户类只关心消息的发送和接收,而不需要直接与其他用户交互?
步骤3:定义具体中介者类
class ConcreteMediator(ChatMediator):def __init__(self):self.users = []def add_user(self, user: User):self.users.append(user)def send_message(self, message: str, user: User):for u in self.users:if u != user:u.receive(message)
问题8:ConcreteMediator
类是如何协调用户之间的消息传递的?它是如何确保消息只被发送给其他用户的?
ConcreteMediator
类维护了所有用户的列表,并在send_message()
方法中将消息发送给除了发送者以外的所有用户。你是否理解,为什么中介者能够管理和协调所有用户之间的消息,而不需要每个用户直接与其他用户交互?
步骤4:客户端代码
def main():mediator = ConcreteMediator()user1 = User("Alice", mediator)user2 = User("Bob", mediator)user3 = User("Charlie", mediator)mediator.add_user(user1)mediator.add_user(user2)mediator.add_user(user3)user1.send("Hello Bob!") # Alice sends message: Hello Bob!user2.send("Hi Alice!") # Bob sends message: Hi Alice!user3.send("Hey everyone!") # Charlie sends message: Hey everyone!if __name__ == "__main__":main()
问题9:在客户端代码中,如何通过中介者来管理用户之间的消息传递?为什么通过中介者来协调消息传递,使得代码更简洁且易于维护?
客户端通过ConcreteMediator
来管理用户之间的消息传递。你是否理解,为什么通过集中管理消息传递,中介者能够减少用户类之间的直接依赖,从而使得代码更加简洁和易于扩展?
中介者模式的优缺点
问题10:中介者模式的优点是什么?它如何帮助我们减少对象间的依赖?
中介者模式通过将对象间的通信集中到一个中介者中,减少了对象之间的直接依赖。你是否理解,这种设计如何让系统更加灵活,且在需要时容易添加新的对象或修改现有的对象行为?
问题11:中介者模式的缺点是什么?它是否可能导致中介者过于复杂,成为系统的瓶颈?
尽管中介者模式有效减少了对象之间的耦合,但它也有可能导致中介者类本身变得过于复杂。你是否认为,如果系统中有太多的交互逻辑被集中到中介者中,可能会使得中介者成为系统的瓶颈?
适用场景
问题12:中介者模式适用于哪些场景?
中介者模式特别适用于以下场景:
-
需要管理多个对象之间的复杂交互,而不希望每个对象直接依赖于其他对象时。
-
当系统中存在多个对象需要协作时,希望通过集中式的协调来简化交互。
-
当对象间的交互逻辑频繁变化时,使用中介者模式能够将变化局限在中介者中,从而避免修改每个对象的代码。
你能想到其他类似的场景吗?例如,GUI界面组件的事件处理、多人在线游戏中的角色协作等,是否也可以使用中介者模式?
问题13:中介者模式是否适用于所有场景?在某些情况下,是否有更合适的设计模式来替代中介者模式?
虽然中介者模式有效简化了对象间的交互,但在某些简单场景中,是否可以直接通过对象间的直接调用来实现?你是否认为,在某些情况下,使用其他模式(如观察者模式)可能更加合适?
接下来,我们将通过具体的代码示例来加深理解中介者模式。
中介者模式深入解读
一、引言
中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介对象来简化对象之间的通信。中介者模式将多个对象之间复杂的交互关系集中在一个中介者对象中,避免了对象之间直接通信的复杂性。通过这种方式,减少了类与类之间的依赖,提高了系统的灵活性和可维护性。
二、简单理解:什么是中介者模式?
1. 什么是中介者模式?
中介者模式的核心思想是:将多个对象之间的交互通过一个中介者对象来集中管理,避免了对象之间复杂的直接通信。中介者对象处理所有的通信逻辑,参与者对象(即需要通信的对象)只需要向中介者发送请求,而不需要直接互相通信。
通俗地讲,中介者模式就像是你在参加一个团队活动。每个成员有自己的任务,但他们之间的沟通并不直接进行,而是通过一个组织者(中介者)来协调每个人的任务,确保大家的工作能够顺利进行。组织者负责将每个人的需求传递给其他成员,避免了每个人直接与其他人沟通,简化了整体的工作流程。
2. 中介者模式的组成部分
中介者模式通常包含以下几个部分:
-
中介者接口(Mediator):定义了与各个同事对象的通信接口。
-
具体中介者类(ConcreteMediator):实现中介者接口,协调各个同事对象之间的通信。
-
同事类(Colleague):每个同事类(对象)知道中介者,并通过中介者与其他同事进行通信。它们不直接与其他同事对象沟通,而是通过中介者进行协作。
-
客户端(Client):通过中介者与同事类交互。
三、用自己的话解释:如何理解中介者模式?
1. 类比实际生活中的场景
假设你参加一个会议,会议上有多个部门的人,每个部门的人都有自己的任务。如果没有中介者(组织者),每个部门的人都需要直接与其他部门沟通,工作流程可能会变得非常复杂。然而,有了组织者(中介者),每个人只需要向组织者反馈信息,组织者会将相关信息传达给其他部门。这样,沟通变得更加简洁和高效。
在编程中,中介者模式将对象之间的复杂通信转交给中介者对象,避免了对象之间直接沟通的复杂性。每个对象只与中介者交互,而不直接与其他对象交互,从而使得代码更加清晰和易于维护。
2. 为什么要使用中介者模式?
使用中介者模式的好处是,它简化了对象之间的通信。通过集中管理通信逻辑,中介者模式避免了多个对象之间相互引用的复杂性。这样,系统中的各个对象不需要知道彼此的细节,它们只需要知道如何与中介者交互。中介者模式还使得对象之间的依赖关系变得松散,提高了系统的可维护性。
四、深入理解:中介者模式的实现
接下来,我们通过一个具体的代码示例来实现中介者模式,帮助你更好地理解如何在代码中使用这个模式。
示例:聊天室系统
假设我们正在开发一个聊天室系统,在这个系统中,用户之间的消息交流是通过聊天室的中介者来完成的。每个用户只与聊天室中介者通信,而不直接与其他用户通信。
1. 定义中介者接口
# 中介者接口:定义所有同事类和中介者之间的通信方法
class ChatMediator:def send_message(self, message: str, user: 'User'):passdef add_user(self, user: 'User'):pass
2. 定义具体中介者类
# 具体中介者类:聊天室
class ChatRoom(ChatMediator):def __init__(self):self.users = []def add_user(self, user: 'User'):self.users.append(user)def send_message(self, message: str, user: 'User'):for u in self.users:if u != user:u.receive_message(message)
3. 定义同事类:用户类
# 同事类:用户
class User:def __init__(self, name: str, mediator: ChatMediator):self.name = nameself.mediator = mediatorself.mediator.add_user(self)def send_message(self, message: str):print(f"{self.name} sends message: {message}")self.mediator.send_message(message, self)def receive_message(self, message: str):print(f"{self.name} receives message: {message}")
4. 客户端代码:使用聊天室进行消息发送
# 客户端代码:创建聊天室和用户对象
chat_room = ChatRoom()user1 = User("Alice", chat_room)
user2 = User("Bob", chat_room)
user3 = User("Charlie", chat_room)# 用户通过中介者发送消息
user1.send_message("Hello, everyone!")
user2.send_message("Hi, Alice!")
user3.send_message("Good morning!")
代码解析:
-
ChatMediator
类:这是中介者接口,定义了消息发送和用户添加的方法。所有的中介者类都需要实现这个接口。 -
ChatRoom
类:这是具体的中介者类,负责管理聊天室中的用户并处理消息的传递。send_message
方法遍历所有用户,将消息传递给其他用户。 -
User
类:这是同事类,表示聊天室中的用户。每个用户都有一个与之关联的中介者(即聊天室)。用户可以通过send_message
方法向聊天室发送消息,而receive_message
方法则接收来自聊天室的消息。 -
客户端代码:在客户端中,我们创建了一个聊天室实例,并创建了多个用户实例。每个用户通过中介者发送消息,而中介者负责将消息转发给其他用户。
五、解释给别人:如何讲解中介者模式?
1. 用简单的语言解释
中介者模式就像是你在一个聊天室里,所有的消息都通过聊天室来转发。你发送的消息并不是直接发送给某个人,而是通过聊天室这个中介者来传递。每个用户只需要知道如何与聊天室进行沟通,而不需要知道其他用户的细节。这样,系统的复杂性就得到了降低,用户之间不需要直接联系,只通过中介者来进行互动。
2. 为什么要使用中介者模式?
使用中介者模式的好处是,它减少了对象之间的依赖关系。通过将通信逻辑集中在中介者对象中,我们避免了多个对象之间相互引用的问题,使得代码更加清晰、简洁。同时,中介者模式也提高了系统的可扩展性,当需要新增用户或修改聊天规则时,不需要修改现有的对象,只需要修改中介者的逻辑即可。
六、总结
中介者模式通过将多个对象间的交互集中到一个中介者对象中,减少了对象间的直接依赖,使得系统更加灵活且易于扩展。然而,过于复杂的中介者可能导致系统瓶颈,因此需要权衡其在复杂系统中的使用。
通过以上学习过程,我们可以得出以下结论:
-
中介者模式 通过引入中介者对象来管理对象之间的通信,避免了多个对象直接交互的复杂性,使得系统更加灵活、可维护。
-
中介者模式适用于那些有多个对象需要交互的场景,并且这些对象之间的交互关系比较复杂。例如聊天室、订单处理系统等可以使用中介者模式来简化交互逻辑。
中介者模式的优点:
-
解耦:对象之间不再直接通信,通过中介者来协调它们的行为,降低了对象之间的依赖关系。
-
简化交互:中介者负责管理复杂的通信逻辑,避免了大量的
if-else
或switch
语句,使得代码更加简洁。 -
提高可维护性:由于所有的通信逻辑都集中在中介者中,修改和扩展系统变得更加容易。
中介者模式的缺点:
-
中介者复杂性:如果系统中的对象数量非常多,所有的通信逻辑可能会集中在一个中介者中,导致中介者变得非常复杂,难以维护。
-
增加中介者的负担:过多的责任可能会使得中介者的职责过重,影响系统性能。
相关文章:
18.中介者模式:思考与解读
原文地址:中介者模式:思考与解读 更多内容请关注:深入思考与解读设计模式 引言 在软件开发中,尤其是处理多个对象交互时,你是否遇到过一个问题:当多个对象需要互相通信时,系统变得复杂,难以管…...

flutter 配置 安卓、Ios启动图
android 配置启动图 launch_background.xml <?xml version"1.0" encoding"utf-8"?> <!-- Modify this file to customize your launch splash screen --> <layer-list xmlns:android"http://schemas.android.com/apk/res/android&…...

基于朴素贝叶斯与 LSTM 的假新闻检测模型对比分析
一、引言 在信息爆炸的时代,假新闻的传播对社会产生了诸多负面影响。如何快速、准确地识别假新闻成为了重要的研究课题。本文将对比传统机器学习算法(朴素贝叶斯)与深度学习模型(LSTM)在假新闻检测任务中的性能表现&am…...

【LeetCode 热题 100】搜索插入位置 / 搜索旋转排序数组 / 寻找旋转排序数组中的最小值
⭐️个人主页:小羊 ⭐️所属专栏:LeetCode 热题 100 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 搜索插入位置搜索二维矩阵在排序数组中查找元素的第一个和最后一个位置搜索旋转排序数组寻找旋转排序数组中的最小值…...

副业小程序YUERGS,从开发到变现
文章目录 我为什么写这个小程序网站转小程序有什么坑有什么推广渠道个人开发者如何变现简单介绍YUERGS小程序给独立开发者一点小建议 我为什么写这个小程序 关注我的粉丝应该知道,我在硕士阶段就已经掌握了小程序开发技能,并写了一个名为“约球online”…...
计算机视觉与深度学习 | Python实现EMD-VMD-LSTM时间序列预测(完整源码和数据)
EMD-VMD-LSTM 一、完整代码实现二、代码结构解析三、关键参数说明四、性能优化建议五、工业部署方案以下是用Python实现EMD-VMD-LSTM时间序列预测的完整代码,结合经验模态分解(EMD)、变分模态分解(VMD)与LSTM深度学习模型,适用于复杂非平稳信号的预测任务。代码包含数据生…...

基于LLM合成高质量情感数据,提升情感分类能力!!
摘要:大多数用于情感分析的数据集缺乏意见表达的上下文,而上下文对于理解情绪往往至关重要,并且这些数据集主要局限于几种情绪类别。像 GPT-4 这样的基础大型语言模型(Foundation Large Language Models,LLMsÿ…...

网络检测工具InternetTest v8.9.1.2504 单文件版,支持一键查询IP/DNS、WIFI密码信息
—————【下 载 地 址】——————— 【本章下载一】:https://drive.uc.cn/s/295e068b79314 【本章下载二】:https://pan.xunlei.com/s/VOQDXguH0DYPxrql5y2zlkhTA1?pwdg2nx# 【百款黑科技】:https://ucnygalh6wle.feishu.cn/wiki/…...
SpringBoot中使用Flux实现流式返回的技术总结
背景 近期在使用deepseek/openai等网页和APP时,发现大模型在思考和回复时,内容是一点点的显示出来的,于是好奇他们的实现方式。经调研和使用开发者工具抓取请求,每次聊天会向后台发送一个http请求,而这个接口跟普通接…...

【网络编程】十、详解 UDP 协议
文章目录 Ⅰ. 传输层概述1、进程之间的通信2、再谈端口号端口号的引出五元组标识一个通信端口号范围划分常见的知名端口号查看知名端口号协议号 VS 端口号 3、两个问题一个端口号是否可以被多个进程绑定?一个进程是否可以绑定多个端口号? 4、部分常见指令…...
从零开始理解Jetty:轻量级Java服务器的入门指南
目录 一、Jetty是什么?先看一个生活比喻 二、5分钟快速入门:搭建你的第一个Jetty服务 步骤1:Maven依赖配置 步骤2:编写简易Servlet(厨房厨师) 步骤3:组装服务器(餐厅开业准备&am…...
python05——循环结构
1、while循环 n0 #初始条件 while n<5: #判断print(hello python) #要重复执行的代码print(n) #注意同级代码缩进相同n1 #计数器结果: hello python 0 hello python 1 hello python 2 hello python 3 hello python 4 hello python 5 #求阶乘和 sum0 n1 whil…...
windows触摸板快捷指南
以下是结构化整理后的触控手势说明,采用清晰的层级划分和标准化表述: **触控手势操作规范****1. 单指操作****2. 双指操作****3. 三指操作****4. 四指操作** **优化说明:** 触控手势操作规范 1. 单指操作 手势功能描述等效操作单击滑动选择…...
STM32 ADC 模数转换器详解:原理、配置与应用
STM32 ADC 模数转换器详解:原理、配置与应用 在嵌入式系统中,模数转换(ADC)是实现传感器信号采集、信号处理等任务的关键环节。STM32 微控制器作为一款功能强大的 32 位微控制器,其内置的 ADC 模块为开发者提供了高效…...

[目标检测] YOLO系列算法讲解
前言 目标检测就是做到给模型输入一张图片或者视频,模型可以迅速判断出视频和图片里面感兴趣的目标所有的位置和它 的类别,而当前最热门的目标检测的模型也就是YOLO系列了。 YOLO系列的模型的提出,是为了解决当时目标检测的模型帧率太低而提…...
React 中,闭包陷阱
文章目录 前言1. 经典闭包陷阱示例过期状态问题 2. 解决方案2.1 正确声明依赖数组2.2 使用 useRef 捕获最新值**2.3 使用函数式更新(针对状态更新)****2.4 使用 useCallback 冻结闭包** **3. 异步操作中的闭包陷阱****事件监听示例** **4. 自定义 Hooks …...

.NET NativeAOT 指南
目录 1. 引言 2. 什么是 .NET NativeAOT? 2.1 NativeAOT 的定义 2.2 NativeAOT 与传统 JIT 的对比 2.3 NativeAOT 的适用场景 3. NativeAOT 的核心优势 3.1 性能提升 3.2 简化部署 3.3 更小的应用体积 3.4 知识产权保护 4. NativeAOT 的基本用法 4.1 环境…...

uniapp-商城-57-后台 新增商品(弹窗属性数据添加父级)
后台增加商品,需要添加相关的数据信息,这里还要添加属性,前面已经对相关的界面布局继续了编写。这里还要对页面添加的数据,置入到云数据库,继续永久保存,便于后期的使用。这里主要是讲属性数据 父级信息的添…...

摩方 12 代 N200 迷你主机(Ubuntu 系统)WiFi 抓包环境配置教程
摩方12代N200迷你主机标配 Intel AX201无线网卡,支持 WiFi 6 协议(802.11ax)及蓝牙5.2。此网卡兼容主流抓包工具,但需注意: 驱动兼容性:Ubuntu 20.04及以上内核版本(5.4)默认支持AX2…...
matlab多智能体网络一致性研究
一个基于连续时间多智能体系统(Multi-Agent Systems, MAS)的一阶一致性协议的MATLAB仿真代码,包含网络拓扑建模、一致性协议设计和收敛性分析。代码支持固定拓扑和时变拓扑,适用于学术研究。 1. 基础模型与代码框架 (1) 网络拓扑…...

Unity(URP渲染管线)的后处理、动画制作、虚拟相机(Virtual Camera)
一、URP渲染管线 渲染管线是一系列渲染操作的集合,Unity提供了内置渲染管线(Built-In)和可编程渲染管线(SRP)两类渲染管线。内置渲染管线是Unity的默认渲染管线,其自定义选项有限。而可编程渲染管线可以通…...
C语言:在 Win 10 上,gcc 如何编译 gtk 应用程序
在 Windows 10 上使用 g(或 gcc)编译基于 GTK 的 C 语言程序是完全可行的,且相比 Tcc 更为推荐,因为 g(GNU 编译器套件)对 GTK 的支持更加完善,配置也更简单。以下是详细步骤和注意事项…...
阿里云CMH镜像迁移与SMC整机迁移对比及功能详解(同地域跨主体账号场景)
文章目录 一、核心功能对比二、CMH镜像迁移操作流程1.资源调研2.镜像共享3.迁移验证4.限制: 三、SMC整机迁移操作流程1.迁移源导入2.任务配置3.增量同步4.应用验证…...
用vue和go实现登录加密
前端使用CryptoJS默认加密方法: var pass CryptoJS.AES.encrypt(formData.password, key.value).toString()使用 CryptoJS.AES.encrypt() 时不指定加密模式和参数时,CryptoJS 默认会执行以下操作 var encrypted CryptoJS.AES.encrypt("明文&quo…...
政府数据开放试点企业如何抢占特许经营协议黄金席位
首席数据官高鹏律师团队 《中共中央办公厅 国务院办公厅关于 加快公共数据资源开发利用的意见》的落地,标志着数据从“封闭管理的行政资源”正式转变为“可流通的市场要素”。但机遇与风险从来是一枚硬币的两面——特许经营协议的黄金席位背后,隐藏着…...
CSS 锚点滑动效果的技术
CSS 锚点滑动效果的技术 引言 介绍锚点滑动效果的概念及其在网页设计中的重要性。简要说明 基本锚点链接 如何使用HTML中的<a>标签创建基本的锚点链接。示例代码: <a href"#section1">跳转到第一部分</a> <div id"section…...

mac-M系列芯片安装软件报错:***已损坏,无法打开。推出磁盘问题
因为你安装的软件在Intel 或arm芯片的mac上没有签名导致。 首先打开任何来源操作 在系统设置中配置,如下图: 2. 然后打开终端,输入: sudo spctl --master-disable然后输入电脑锁屏密码 打开了任何来源,还遇到已损坏…...

Echart地图数据源获取
DataV.GeoAtlas地理小工具系列 选择需要的区域地图,选中后输出即可: 地图钻取代码 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>map</title><style>html, body, #map{margin: 0;…...

GNSS数据自动化下载系统的设计与实现
摘要 本文详细介绍了三种不同设计的GNSS数据自动化下载系统,分别针对IGS观测数据、GRACE-FO Level-1B数据以及通过代理服务器获取数据的需求场景。系统采用Python实现,具备断点续传、完整性校验、异常处理和进度显示等核心功能。实验结果表明࿰…...
MySQL 中 JOIN 和子查询的区别与使用场景
目录 一、JOIN:表连接1.1 INNER JOIN:内连接1.2 LEFT JOIN:左连接1.3 RIGHT JOIN:右连接1.4 FULL JOIN:全连接二、子查询:嵌套查询2.1 WHERE 子句中的子查询2.2 FROM 子句中的子查询2.3 SELECT 子句中的子查询三、JOIN 和子查询的区别3.1 功能差异3.2 性能差异3.3 使用场…...