解密Java中介者模式:代码实例带你深入理解
1. 引言:中介者模式的重要性
在软件设计的世界里,模块间的相互依赖往往会导致系统的复杂性和维护难度的增加。中介者模式(Mediator Pattern)作为一种行为设计模式,它的出现就是为了解决这一问题。通过引入一个中介者对象,它能够协调各个模块之间的通信,从而实现模块间的解耦,提高系统的灵活性和可维护性。
1.1 中介者模式在软件设计中的作用
中介者模式的核心思想是定义一个中介对象来封装一系列对象之间的交互。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。这种模式在需要处理多个对象之间的复杂网络关系时尤其有用,它能够简化对象之间的通信,并使得系统更易于管理和扩展。
1.2 中介者模式与系统解耦
系统解耦是软件设计中的一个重要目标,它意味着各个模块或组件之间应该尽可能地独立,减少直接的依赖关系。中介者模式通过集中控制对象间的交互,有效地减少了对象间的直接耦合。这种解耦不仅使得系统更加灵活,而且当系统需要扩展或修改时,只需要调整中介者对象,而不需要修改其他对象,从而大大降低了系统的维护成本。
2. 中介者模式概述
中介者模式是一种设计模式,它允许我们通过引入一个中介对象来简化复杂对象之间的通信。这种模式通过将对象间的直接通信转化为通过中介者进行间接通信,从而降低了系统的耦合度。
2.1 定义与核心概念
中介者模式定义了一个中介对象,用于封装一组对象之间的交互。这些对象称为同事(Colleague)对象。中介者模式的核心概念包括:
- 中介者(Mediator):定义了一个接口,用于与各同事对象通信。
- 具体中介者(Concrete Mediator):实现了中介者接口,协调各同事对象,了解并维护这些对象。
- 同事类(Colleague):每个同事类都知道它的中介者对象,并且与中介者通信,而不是与其他同事类直接通信。
通过这种方式,中介者模式将系统的网状结构转化为星型结构,从而简化了对象间的交互。
2.2 中介者模式的角色与职责
在中介者模式中,各个角色的职责如下:
-
中介者(Mediator):
- 定义同事对象之间交互的接口。
- 知道并管理所有的同事对象。
- 接收同事对象的请求,并协调相应的同事对象进行响应。
-
具体中介者(Concrete Mediator):
- 实现中介者接口。
- 协调各个同事对象的行为。
- 可能需要了解并维护同事对象的状态。
-
同事类(Colleague):
- 每个同事类都知道它的中介者对象。
- 当需要与其他同事类通信时,通过中介者进行。
- 通常只与中介者进行交互,而不直接与其他同事类交互。
通过这些角色的明确分工,中介者模式有效地将对象间的复杂交互转化为中介者与同事类之间的简单交互,从而提高了系统的可维护性和扩展性。
3. 中介者模式的UML类图解析
3.1 类图结构详解
中介者模式的UML类图主要包括以下几个部分:
- Mediator(中介者):这是中介者模式的中心角色,负责协调各个同事对象之间的交互。
- Colleague(同事):这是直接与中介者交互的角色,通常会定义一个中介者引用,以便通过中介者与其他同事进行通信。
- ConcreteMediator(具体中介者):实现中介者接口的具体类,负责具体的中介者逻辑。
- ConcreteColleagueA/ConcreteColleagueB(具体同事类):实现同事接口的具体类,每个具体同事类都可以与中介者进行交互。
3.2 角色间的交互关系
在类图中,角色间的交互关系主要体现在以下几个方面:
- 中介者与同事:具体中介者类与具体同事类之间存在关联关系,具体中介者类通常包含一个同事类的集合,用于管理所有同事对象。
- 同事与中介者:具体同事类中包含对中介者的引用,通过这个引用,具体同事类可以与中介者进行交互,以实现与其他同事的通信。
- 同事与同事:在具体实现中,同事类之间不直接交互,而是通过中介者进行交互。这样,具体同事类之间的耦合度大大降低,提高了系统的灵活性和可维护性。
3.3 UML类图示例
4. 中介者模式的实现步骤
实现中介者模式通常包括以下几个步骤。
4.1 创建中介者接口与具体中介者
首先,我们需要定义一个中介者接口,它描述了同事对象之间交互的接口。然后,实现这个接口,创建一个具体的中介者类,它负责协调各个同事对象的行为。
// 中介者接口
public interface Mediator {void send(String message, Colleague colleague);void receive(String message, Colleague colleague);
}// 具体中介者类
public class ConcreteMediator implements Mediator {private ColleagueA colleagueA;private ColleagueB colleagueB;public ConcreteMediator(ColleagueA colleagueA, ColleagueB colleagueB) {this.colleagueA = colleagueA;this.colleagueB = colleagueB;}@Overridepublic void send(String message, Colleague colleague) {if (colleague == colleagueA) {colleagueB.receive(message, colleague);} else if (colleague == colleagueB) {colleagueA.receive(message, colleague);}}@Overridepublic void receive(String message, Colleague colleague) {// 处理接收到的消息System.out.println(colleague + " received: " + message);}
}
4.2 定义同事类及其与中介者的交互
接下来,我们需要定义同事类,并实现它们与中介者的交互。同事类通常会维护对中介者的引用,以便与中介者进行通信。
// 同事类基类
public abstract class Colleague {protected Mediator mediator;public Colleague(Mediator mediator) {this.mediator = mediator;}// 抽象方法,同事类的具体交互逻辑public abstract void receive(String message, Colleague colleague);
}// 具体同事类A
public class ColleagueA extends Colleague {public ColleagueA(Mediator mediator) {super(mediator);}@Overridepublic void receive(String message, Colleague colleague) {if (colleague instanceof ColleagueB) {System.out.println("ColleagueA received: " + message);// 处理接收到的消息,可能需要回复String reply = processMessage(message);mediator.send(reply, this);}}private String processMessage(String message) {// 处理消息并返回回复return "Response from A";}
}// 具体同事类B
public class ColleagueB extends Colleague {public ColleagueB(Mediator mediator) {super(mediator);}@Overridepublic void receive(String message, Colleague colleague) {if (colleague instanceof ColleagueA) {System.out.println("ColleagueB received: " + message);// 处理接收到的消息,可能需要回复String reply = processMessage(message);mediator.send(reply, this);}}private String processMessage(String message) {// 处理消息并返回回复return "Response from B";}
}
在这段代码中,我们定义了一个中介者接口和两个具体的中介者实现,以及两个同事类及其具体实现。每个同事类都包含一个receive
方法,用于处理从中介者接收到的消息,并可能需要回复中介者。中介者类则负责转发消息,协调同事类之间的交互。
5. 代码实例:聊天室系统
5.1 系统需求与设计思路
假设我们正在设计一个简单的聊天室系统,用户可以发送消息给其他用户,系统需要处理这些消息并将其转发给目标用户。为了实现解耦,我们使用中介者模式来处理用户之间的交互。
设计思路如下:
- 用户(User):可以发送消息给其他用户,也可以接收来自其他用户的消息。
- 中介者(Chatroom):负责管理所有用户,处理用户之间的消息传递。
5.2 实现中介者接口与具体中介者
首先,我们定义中介者接口和具体中介者类。
// 中介者接口
public interface Chatroom {void sendMessage(String message, User sender, User receiver);void receiveMessage(String message, User sender, User receiver);
}// 具体中介者类
public class ConcreteChatroom implements Chatroom {private Map<String, User> users = new HashMap<>();@Overridepublic void sendMessage(String message, User sender, User receiver) {receiver.receiveMessage(message, sender, this);}@Overridepublic void receiveMessage(String message, User sender, User receiver) {System.out.println(sender.getName() + " to " + receiver.getName() + ": " + message);}public void registerUser(User user) {users.put(user.getName(), user);}
}
5.3 实现用户类(同事类)
接下来,我们实现用户类。
// 用户类
public class User {private String name;private Chatroom chatroom;public User(String name, Chatroom chatroom) {this.name = name;this.chatroom = chatroom;}public void sendMessage(String message, User sender, User receiver) {chatroom.sendMessage(message, sender, receiver);}public void receiveMessage(String message, User sender, User receiver) {System.out.println(sender.getName() + " to " + this.name + ": " + message);}
}
5.4 用户与中介者的交互逻辑
现在,我们来模拟用户之间的交互逻辑。
public class ChatroomDemo {public static void main(String[] args) {Chatroom chatroom = new ConcreteChatroom();User alice = new User("Alice", chatroom);User bob = new User("Bob", chatroom);chatroom.registerUser(alice);chatroom.registerUser(bob);alice.sendMessage("Hello, Bob!", alice, bob);bob.sendMessage("Hi, Alice!", bob, alice);}
}
在这个例子中,我们创建了一个聊天室中介者和两个用户(Alice和Bob)。每个用户都可以发送消息给其他用户,而中介者负责将消息转发给目标用户。这样,用户之间不需要知道对方的存在,只需要通过中介者进行通信,实现了用户之间的解耦。
6. 代码实例:航空交通控制系统
6.1 系统需求与设计思路
在航空交通控制系统的设计中,我们需要处理多架飞机之间的动态关系,如起飞、降落、避让等。为了简化对象之间的交互,我们采用中介者模式来实现这一系统。
设计思路如下:
- 飞机(Plane):能够发送和接收与其他飞机的交互信息,如请求降落、请求起飞、通知避让等。
- 交通控制器(AirTrafficController):作为中介者,负责协调和管理所有飞机的行为。
6.2 实现中介者接口与具体中介者
首先,我们定义中介者接口和具体中介者类。
// 中介者接口
public interface AirTrafficController {void sendRequest(Plane plane, String request, Plane target);void receiveRequest(Plane plane, String request, Plane target);
}// 具体中介者类
public class ConcreteAirTrafficController implements AirTrafficController {private Map<String, Plane> planes = new HashMap<>();@Overridepublic void sendRequest(Plane plane, String request, Plane target) {target.receiveRequest(request, plane, this);}@Overridepublic void receiveRequest(Plane plane, String request, Plane target) {System.out.println(plane.getId() + " to " + target.getId() + ": " + request);// 根据请求类型处理飞机之间的交互switch (request) {case "Request Landing":// 处理降落请求break;case "Request Takeoff":// 处理起飞请求break;case "Request Avoidance":// 处理避让请求break;}}public void registerPlane(Plane plane) {planes.put(plane.getId(), plane);}
}
6.3 实现飞机类(同事类)
接下来,我们实现飞机类。
// 飞机类
public class Plane {private String id;private AirTrafficController atc;public Plane(String id, AirTrafficController atc) {this.id = id;this.atc = atc;}public void sendRequest(String request, Plane target) {atc.sendRequest(this, request, target);}public void receiveRequest(String request, Plane sender, AirTrafficController atc) {System.out.println(sender.getId() + " to " + this.id + ": " + request);// 根据请求类型处理与目标飞机的交互switch (request) {case "Request Landing":// 处理降落请求break;case "Request Takeoff":// 处理起飞请求break;case "Request Avoidance":// 处理避让请求break;}}
}
6.4 飞机与中介者的交互逻辑
现在,我们来模拟飞机之间的交互逻辑。
public class AirTrafficControlDemo {public static void main(String[] args) {AirTrafficController atc = new ConcreteAirTrafficController();Plane plane1 = new Plane("Plane1", atc);Plane plane2 = new Plane("Plane2", atc);atc.registerPlane(plane1);atc.registerPlane(plane2);plane1.sendRequest("Request Takeoff", plane2);plane2.sendRequest("Request Landing", plane1);}
}
在这个例子中,我们创建了一个航空交通控制器和两架飞机。飞机可以发送请求给其他飞机,而交通控制器负责协调和管理这些请求。通过这种方式,飞机之间不需要直接通信,而是通过交通控制器进行交互,实现了飞机之间的解耦。
7. 中介者模式的优缺点分析
7.1 优点:解耦、简化对象交互
中介者模式的主要优点在于它能够显著地降低对象之间的耦合度。通过引入一个中介者对象,对象之间的直接交互被转化为通过中介者进行的间接交互。这样,对象不需要知道其他对象的存在,只需要知道中介者。这种解耦不仅使系统更加灵活,而且当系统需要扩展或修改时,只需要调整中介者对象,而不需要修改其他对象,从而大大降低了系统的维护成本。
此外,中介者模式还可以简化对象之间的交互。对象不再需要处理复杂的网状交互,而是通过简单地与中介者进行交互来完成它们的工作。这使得系统的逻辑更加清晰,易于理解和维护。
7.2 缺点:中介者可能变得复杂
尽管中介者模式有许多优点,但它也存在一些潜在的缺点。最主要的缺点是中介者对象可能变得非常复杂。因为中介者需要知道所有同事对象的状态和它们之间的交互,所以它可能会变得非常庞大和难以管理。
当系统中的对象数量增加时,中介者需要维护的对象数量也会增加。这可能导致中介者对象变得非常复杂,难以理解和维护。此外,如果中介者对象出现故障,整个系统可能会受到影响,因为所有的交互都依赖于中介者。
总的来说,中介者模式是一种非常有用的设计模式,特别是当需要处理多个对象之间的复杂交互时。然而,在实际应用中,需要仔细考虑中介者对象的设计,以避免其变得过于复杂和难以管理。
8. 中介者模式的应用场景
8.1 何时使用中介者模式
中介者模式适用于以下场景:
- 对象之间存在复杂的网状依赖关系:当多个对象之间存在复杂的相互依赖和通信时,中介者模式可以帮助简化这些依赖关系。
- 需要解耦多个对象:当需要降低对象之间的耦合度,以便更灵活地扩展或修改系统时,可以使用中介者模式。
- 多个对象之间的交互依赖于中介者:当对象之间的交互依赖于中介者提供的协调时,中介者模式可以简化这些交互。
- 对象数量较少:尽管中介者模式适用于处理多个对象之间的交互,但在对象数量较少的情况下,使用中介者模式可能显得有些过度复杂。
8.2 实际应用案例分析
中介者模式在实际应用中非常广泛,以下是一些常见的应用案例:
-
图形编辑器:在图形编辑器中,多个图形对象(如矩形、圆形、文本等)可能需要相互交互,如组合、分离、变换等。使用中介者模式可以简化这些对象之间的依赖关系。
-
网络通信:在网络通信中,不同的客户端和服务器可能需要进行交互。中介者模式可以用来简化这些客户端和服务器之间的通信逻辑。
-
数据库事务管理:在数据库事务管理中,多个事务对象可能需要相互协调和同步。使用中介者模式可以简化这些事务对象之间的交互。
-
企业信息系统:在企业信息系统中,多个业务对象(如订单、客户、产品等)可能需要相互协作。中介者模式可以用来简化这些业务对象之间的依赖关系。
-
游戏设计:在游戏设计中,多个游戏对象(如玩家、敌人、道具等)可能需要相互交互。使用中介者模式可以简化这些游戏对象之间的依赖关系。
相关文章:

解密Java中介者模式:代码实例带你深入理解
1. 引言:中介者模式的重要性 在软件设计的世界里,模块间的相互依赖往往会导致系统的复杂性和维护难度的增加。中介者模式(Mediator Pattern)作为一种行为设计模式,它的出现就是为了解决这一问题。通过引入一个中介者对…...

19c做好这件事,大幅提升Data Pump工作效率
老司机遇到的新问题 expdp是Oracle 10g引入的数据导出工具,能够提供并行、压缩及元数据导出等更多的功能,在后续的版本中逐渐替代了传统的数据导出工具exp,是数据库开发运维常用的工具之一。在我的印象中,这个工具除了诸如大量的…...

6种常用的AR跟踪方法
增强现实 (AR) 是一项令人着迷的技术,可将虚拟内容与现实世界无缝集成。实现这种无缝集成的关键组件之一是跟踪。各种类型的跟踪用于确定 AR 内容在环境中的准确位置和方向。本文介绍 AR 最常见的6种跟踪方法。 NSDT工具推荐: Three.js AI纹理开发包 - Y…...

HBO引爆血腥浪漫,尺度全开必看的影视剧推荐
一直以来我们的僵尸题材电影风靡全国,同时西方也创作出吸血鬼题材、丧尸题材的影视剧也是层出不穷,那今天我们就来探讨下吸血鬼题材的影视剧。 吸血鬼题材的影视剧,一直以来都是观众的宠儿。从光鲜亮丽的《暮光之城》到狗血多角恋的《吸血鬼日…...

【kubernetes】pod控制器详解
一、pod控制器概述 1、Pod控制器作用 Pod控制器,是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试进行重启,当根据重启策略无效,则会重新新建pod的资源。 2、pod控制器…...

Zookeeper学习、Tomcat
怎样使用Zookeeper实现服务发现? 典型回答 服务发现是ZK的重要用途之一,当我们想要基于zk实现服务发现时,一般可以参考以下步骤:1. 向Zookeeper注册服务 服务提供者需要在Zookeeper上创建一个临时节点来注册自己的服务。节点的名…...

软件测试基础知识与面试题最强总结(2024版)
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、什么是软件? 软件是计算机系统中的程序和相关文件或文档的总称。 二、什么是软件测试? 说法一:使用人工或自动的手段来运…...

ESP32播放网络音频文件
要使用ESP32播放网络上的音频文件,你可以通过以下步骤实现。ESP32可以使用Wi-Fi连接到互联网,下载音频文件并通过I2S接口输出音频数据。以下是一个示例,展示如何使用ESP32从URL获取音频文件并播放。 ESP32开发板。I2S DAC(如MAX9…...

端到端 AWS 定量分析:使用 AWS 和 AWSCLI 自动运行脚本
使用 AWSCLI 启动、运行和关闭 AWS 服务器 添加图片注释,不超过 140 字(可选) 欢迎来到雲闪世界。我们开发了两个 Python 脚本;一个用于为我们获取数据,另一个用于使用 sklearn 的决策树分类器处理数据。然后…...

数据结构与算法 - B树
一、概述 1. 历史 B树(B-Tree)结构是一种高效存储和查询数据的方法,它的历史可以追溯到1970年代早期。B树的发明人Rudolf Bayer和Edward M. McCreight分别发表了一篇论文介绍了B树。这篇论文是1972年发表于《ACM Transactions on Database Systems》中的ÿ…...

Java二十三种设计模式-观察者模式(15/23)
观察者模式:实现对象间的松耦合通知机制 引言 在当今的软件开发领域,设计模式已成为创建可维护、可扩展和可重用代码的基石。在众多设计模式中,观察者模式以其独特的能力,实现对象间的松耦合通信而脱颖而出。本文将深入探讨观察…...

opencv-python图像增强二:图像去雾(暗通道去雾)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、简介:二、暗通道去雾方案简述:三、算法实现步骤3.1最小值滤波3.2 引导滤波3.3 计算图像全局光强 四:整体代码实现五…...

自研Vue3低代码海报制作平台第一步:基础拖拽组件开发
学习来源:稀土掘金 - 幽月之格大佬的技术专栏可拖拽、缩放、旋转组件 - 著作:可拖拽、缩放、旋转组件实现细节 非常感谢大佬!受益匪浅! 前面我们学习了很多vue3的知识,是时候把它们用起来做一个有意思的平台…...

QT 的 QSettings 读写 INI 文件的示例
在Qt中,QSettings 类提供了一种便捷的方式来存储和访问应用程序的设置,这些设置可以存储在多种格式的文件中,包括INI、Windows注册表(仅Windows平台)、XML和JSON等。以下是一些使用 QSettings 读写INI文件的示例。 写…...

【零基础学习CAPL语法】——testStep:测试结果输出函数
文章目录 1.函数介绍2.在报告中体现 1.函数介绍 testStep——测试结果输出函数 2.在报告中体现 //testStep() void PrintTxMsg() {testStep("Tx","[%x] [%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x]",Diag_Req.id,Diag_Req.byte(0),Diag_Req.byte(1),Di…...

8.5.数据库基础技术-规范化
函数依赖 函数依赖:给定一个X,能唯一确定一个Y,就称X决定(确定)Y,或者说Y依赖于X。 例如:YX*X函数,此时X能确定Y的值,但是Y无法确定X的值,比如x2,y4,但是y4无法确定x2。函数依赖又可扩展以下两…...

于博士Cadence视频教程学习笔记备忘
标签:PCB教程 PCB设计步骤 cadence教程 Allegro教程 以下是我学习该视频教程的笔记,记录下备忘,欢迎大家在此基础上完善,能回传我一份是最好了,先谢过。 备注: 1、未掌握即未进行操作 2、操作软件是15.…...

8.3.数据库基础技术-关系代数
并:结果是两张表中所有记录数合并,相同记录只显示一次。交:结果是两张表中相同的记录。差:S1-S2,结果是S1表中有而S2表中没有的那些记录。 笛卡尔积:S1XS2,产生的结果包括S1和S2的所有属性列,并且S1中每条记…...

【Vue3】vue模板中如何使用enum枚举类型
简言 有的时候,我们想在vue模板中直接使用枚举类型的值,来做一些判断。 ts枚举 枚举允许开发人员定义一组命名常量。使用枚举可以更容易地记录意图,或创建一组不同的情况。TypeScript 提供了基于数字和字符串的枚举。 枚举的定义这里不说了…...

组合求和2
题目描述: Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target. Each number in candidates may only be used once in the combinati…...

Apple Maps现在可在Firefox和Mac版Edge浏览器中使用
Apple Maps最初只能在 Windows 版 Safari、Chrome 浏览器和 Edge 浏览器上运行,现在已在其他浏览器上运行,包括 Mac 版 Firefox 和 Edge。经过十多年的等待,Apple Maps于今年 7 月推出了新版地图应用的测试版,但只能在有限的浏览器…...

基于嵌入式Linux的数据库
数据库 数据库是在数据库管理系统和控制之下,存放在存储 介质上的数据集合。 基于嵌入式的数据库 基于嵌入式linux的数据库主要有SQlite, Firebird,Berkeley DB,eXtremeDB Firebird是关系型数据库,功能强大,支持存储过 程&…...

C# 使用LINQ找出一个子字符串在另一个字符串中出现的所有位置
一、实现步骤 遍历主字符串,使用IndexOf方法查找子字符串的位置。如果找到了子字符串,记录其位置,并且从该位置的后面继续查找。重复上述步骤直到遍历完整个字符串。 二、简单代码示例 using System; using System.Collections.Generic; usi…...

YOLOv8添加MobileViTv3模块(代码+free)
目录 一、理由 二、方法 (1)导入MobileViTv3模块 (2)在ultralytics/nn/tasks.py的函数parse_model中修改 (3)在yaml配置文件中写入 (4)开始训练,先把其他梯度关闭&…...

从概念到落地:全面解析DApp项目开发的核心要素与未来趋势
随着区块链技术的迅猛发展,去中心化应用程序(DApp)逐渐成为Web3时代的重要组成部分。DApp通过智能合约和分布式账本技术,提供了无需信任中介的解决方案,这种去中心化的特性使其在金融、游戏、社交等多个领域得到了广泛…...

仓颉编程入门 -- 泛型概述 , 如何定义泛型函数
泛型概述 , 如何定义泛型函数 1 . 泛型的定义 在仓颉编程语言中,泛型机制允许我们定义参数化类型,这些类型在声明时不具体指定其操作的数据类型,而是作为类型形参保留,待使用时通过类型实参来明确。这种灵活性在函数和类型声明中…...

SOC估算方法之(OCV-SOC+安时积分法)
一、引言 此方法主要参考电动汽车用磷酸铁锂电池SOC估算方法这篇论文 总结: 开路电压的测量需要将电池静止相当长的一段时间才能达到平衡状态进行测量。 安时积分法存在初始SOC的估算和累积的误差。 所以上述两种方法都存在一定的缺陷,因此下面主要讲…...

指针(下)
文章目录 指针(下)野指针、空指针野指针空指针 二级指针**main**函数的原型说明 常量指针与指针常量常量指针指针常量常量指针常量 动态内存分配常用函数**malloc****calloc****realloc****free** **void**与**void***的区别扩展:形式参数和实际参数的对应关系 指针…...

C# 浅谈IEnumerable
一、IEnumerable 简介 IEnumerable 是一个接口,它定义了对集合进行迭代所需的方法。IEnumerable 接口主要用于允许开发者使用foreach循环来遍历集合中的元素。这个接口定义了一个名为 GetEnumerator 的方法,该方法返回一个实现了 IEnumerator 接口的对象…...

mmdebstrap:创建 Debian 系统 chroot 环境的利器 ️
文章目录 mmdebstrap 的一般性参数说明 📜mmdebstrap 的常见用法示例 🌈使用 mmdebstrap 的注意事项 ⚠️ 🌈你好呀!我是 山顶风景独好 🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然&am…...