<摘要>
中介者模式是一种行为设计模式,通过引入中介者对象来封装一组对象之间的交互,从而降低对象间的耦合度。本文将详细解析中介者模式的背景概念、设计意图、实现方式及应用场景,通过聊天室系统、飞机调度系统和UI组件交互三个完整案例,结合C++代码实现和Mermaid图表,全面展示该模式的实际应用价值。
<解析>
中介者模式深度解析
1. 背景与核心概念
1.1 起源与发展历程
中介者模式的诞生可以追溯到软件工程中"高内聚、低耦合"的设计原则。在早期的面向对象设计中,开发人员经常遇到这样的困境:当多个对象需要相互通信时,直接的对象引用会导致复杂的网状依赖关系。
发展脉络:
- 1987年:在Smalltalk语言的MVC框架中首次出现了类似中介者的概念
- 1994年:Gamma等人在《设计模式》一书中正式提出并定义了中介者模式
- 2000年代:随着GUI框架和企业级应用的发展,中介者模式得到广泛应用
- 现今:在微服务架构、事件驱动系统中,中介者模式的思想被重新诠释和应用
1.2 核心概念解析
中介者模式的核心思想是:用一个中介对象来封装一系列的对象交互,使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
关键术语:
术语 | 英文 | 说明 |
---|---|---|
中介者 | Mediator | 定义对象间交互的接口 |
具体中介者 | ConcreteMediator | 实现中介者接口,协调各同事对象 |
同事类 | Colleague | 定义同事类的接口,持有中介者引用 |
具体同事类 | ConcreteColleague | 实现同事类接口,只与中介者通信 |
1.3 UML类图解析
图表解读:
- Mediator:抽象中介者,定义通信接口
- ConcreteMediator:具体中介者,维护同事对象引用,实现复杂的协调逻辑
- Colleague:同事抽象类,包含中介者引用
- ConcreteColleague:具体同事类,通过中介者与其他对象通信
2. 设计意图与考量
2.1 核心设计目标
中介者模式的核心设计目标可以用"解耦"二字概括,具体体现在:
- 降低耦合度:将网状依赖变为星状依赖
- 集中控制:将交互逻辑集中到中介者中
- 简化对象职责:每个对象只需关注自身业务逻辑
- 提高复用性:同事类可以独立复用
2.2 设计权衡因素
优势:
- ✅ 减少类间依赖,降低耦合
- ✅ 简化对象协议,一对多交互变为一对一
- ✅ 抽象对象交互,便于理解和维护
- ✅ 符合迪米特法则(最少知识原则)
劣势:
- ❌ 中介者可能变得过于复杂,成为"上帝对象"
- ❌ 增加了系统的中间层,可能影响性能
- ❌ 中介者本身的修改可能影响整个系统
2.3 适用场景分析
适合使用中介者模式的场景:
- 对象间存在复杂的网状引用关系
- 一个对象引用很多其他对象,直接通信导致难以复用
- 想在多个对象间定制交互行为,又不想生成太多子类
- 交互行为需要定义在不同对象间,但又不想分散在各个类中
3. 实例与应用场景
3.1 案例一:智能聊天室系统
场景描述:
设计一个多人聊天室系统,用户可以向所有人广播消息,也可以私聊特定用户,同时需要支持用户加入、离开的通知。
实现方案:
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
// 前向声明
class User;
/**
* @brief 聊天室中介者接口
*
* 定义用户间通信的标准接口,负责协调所有用户对象之间的交互
*/
class ChatMediator {
public:
virtual ~ChatMediator() = default;
/**
* @brief 发送消息到所有用户
*
* @param message 消息内容
* @param sender 发送者
*/
virtual void broadcastMessage(const std::string& message,
const std::string& sender) = 0;
/**
* @brief 发送私聊消息
*
* @param message 消息内容
* @param sender 发送者
* @param receiver 接收者
*/
virtual void privateMessage(const std::string& message,
const std::string& sender,
const std::string& receiver) = 0;
/**
* @brief 用户加入聊天室
*
* @param user 用户对象
*/
virtual void addUser(std::shared_ptr<User> user) = 0;
/**
* @brief 用户离开聊天室
*
* @param username 用户名
*/
virtual void removeUser(const std::string& username) = 0;
};
/**
* @brief 用户抽象类(同事类)
*
* 定义用户的基本行为和属性,持有中介者引用
*/
class User {
protected:
std::string username_;
std::shared_ptr<ChatMediator> mediator_;
public:
User(const std::string& username, std::shared_ptr<ChatMediator> mediator)
: username_(username), mediator_(mediator) {}
virtual ~User() = default;
/**
* @brief 获取用户名
*
* @return std::string 用户名
*/
std::string getUsername() const { return username_; }
/**
* @brief 发送广播消息
*
* @param message 消息内容
*/
virtual void sendMessage(const std::string& message) {
std::cout << username_ << " 发送广播: " << message << std::endl;
mediator_->broadcastMessage(message, username_);
}
/**
* @brief 发送私聊消息
*
* @param message 消息内容
* @param receiver 接收者用户名
*/
virtual void sendPrivateMessage(const std::string& message,
const std::string& receiver) {
std::cout << username_ << " 私聊 " << receiver << ": " << message << std::endl;
mediator_->privateMessage(message, username_, receiver);
}
/**
* @brief 接收消息
*
* @param message 消息内容
* @param sender 发送者
*/
virtual void receiveMessage(const std::string& message,
const std::string& sender) = 0;
};
/**
* @brief 具体用户类
*
* 实现具体的用户行为,可以扩展不同的用户类型
*/
class ChatUser : public User {
public:
ChatUser(const std::string& username, std::shared_ptr<ChatMediator> mediator)
: User(username, mediator) {}
void receiveMessage(const std::string& message,
const std::string& sender) override {
std::cout << username_ << " 收到来自 " << sender << " 的消息: "
<< message << std::endl;
}
};
/**
* @brief 具体聊天室中介者
*
* 实现聊天室的具体逻辑,管理所有用户和消息路由
*/
class ConcreteChatMediator : public ChatMediator {
private:
std::unordered_map<std::string, std::shared_ptr<User>> users_;
public:
void broadcastMessage(const std::string& message,
const std::string& sender) override {
std::cout << "=== 聊天室广播 === (" << sender << "): "
<< message << std::endl;
for (const auto& pair : users_) {
if (pair.first != sender) { // 不发送给自己
pair.second->receiveMessage(message, sender);
}
}
}
void privateMessage(const std::string& message,
const std::string& sender,
const std::string& receiver) override {
std::cout << "=== 私聊消息 === [" << sender << " -> "
<< receiver << "]: " << message << std::endl;
auto it = users_.find(receiver);
if (it != users_.end()) {
it->second->receiveMessage("[私聊] " + message, sender);
} else {
// 通知发送者接收者不存在
auto senderIt = users_.find(sender);
if (senderIt != users_.end()) {
senderIt->second->receiveMessage("错误: 用户 " + receiver + " 不存在", "系统");
}
}
}
void addUser(std::shared_ptr<User> user) override {
std::string username = user->getUsername();
users_[username] = user;
// 通知所有用户有新用户加入
broadcastMessage("用户 " + username + " 加入了聊天室", "系统");
}
void removeUser(const std::string& username) override {
auto it = users_.find(username);
if (it != users_.end()) {
users_.erase(it);
broadcastMessage("用户 " + username + " 离开了聊天室", "系统");
}
}
};
// 演示代码
int main() {
// 创建聊天室中介者
auto chatMediator = std::make_shared<ConcreteChatMediator>();
// 创建用户
auto user1 = std::make_shared<ChatUser>("Alice", chatMediator);
auto user2 = std::make_shared<ChatUser>("Bob", chatMediator);
auto user3 = std::make_shared<ChatUser>("Charlie", chatMediator);
// 用户加入聊天室
chatMediator->addUser(user1);
chatMediator->addUser(user2);
chatMediator->addUser(user3);
std::cout << "\n=== 聊天开始 ===\n" << std::endl;
// 用户间通信
user1->sendMessage("大家好!");
user2->sendMessage("你好,Alice!");
user1->sendPrivateMessage("嘿,Bob,有个秘密要告诉你", "Bob");
user3->sendMessage("我也可以看到广播消息");
// Bob离开聊天室
chatMediator->removeUser("Bob");
// 再次尝试给Bob发消息
user1->sendPrivateMessage("Bob,你还在吗?", "Bob");
return 0;
}
时序图分析:
3.2 案例二:飞机调度系统
场景描述:
设计一个航空管制系统,多架飞机需要与塔台通信,飞机之间不能直接通信,必须通过塔台中介者来协调起飞、降落和航线冲突。
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <algorithm>
// 飞机状态枚举
enum class FlightStatus {
ON_GROUND,
TAKING_OFF,
IN_AIR,
LANDING
};
/**
* @brief 航空管制中介者接口
*
* 协调所有飞机的起降和飞行状态,避免冲突
*/
class AirTrafficControl {
public:
virtual ~AirTrafficControl() = default;
/**
* @brief 请求起飞
*
* @param flightId 航班号
* @return bool 是否允许起飞
*/
virtual bool requestTakeoff(const std::string& flightId) = 0;
/**
* @brief 请求降落
*
* @param flightId 航班号
* @return bool 是否允许降落
*/
virtual bool requestLanding(const std::string& flightId) = 0;
/**
* @brief 通知起飞完成
*
* @param flightId 航班号
*/
virtual void notifyTakeoffComplete(const std::string& flightId) = 0;
/**
* @brief 通知降落完成
*
* @param flightId 航班号
*/
virtual void notifyLandingComplete(const std::string& flightId) = 0;
/**
* @brief 注册飞机
*
* @param aircraft 飞机对象
*/
virtual void registerAircraft(std::shared_ptr<class Aircraft> aircraft) = 0;
};
/**
* @brief 飞机抽象类
*
* 定义飞机的基本行为和状态
*/
class Aircraft {
protected:
std::string flightId_;
FlightStatus status_;
std::shared_ptr<AirTrafficControl> atc_;
public:
Aircraft(const std::string& flightId, std::shared_ptr<AirTrafficControl> atc)
: flightId_(flightId), status_(FlightStatus::ON_GROUND), atc_(atc) {}
virtual ~Aircraft() = default;
std::string getFlightId() const { return flightId_; }
FlightStatus getStatus() const { return status_; }
/**
* @brief 请求起飞
*/
virtual void requestTakeoff() {
std::cout << "航班 " << flightId_ << " 请求起飞" << std::endl;
if (atc_->requestTakeoff(flightId_)) {
status_ = FlightStatus::TAKING_OFF;
std::cout << "航班 " << flightId_ << " 开始起飞" << std::endl;
} else {
std::cout << "航班 " << flightId_ << " 起飞请求被拒绝" << std::endl;
}
}
/**
* @brief 请求降落
*/
virtual void requestLanding() {
std::cout << "航班 " << flightId_ << " 请求降落" << std::endl;
if (atc_->requestLanding(flightId_)) {
status_ = FlightStatus::LANDING;
std::cout << "航班 " << flightId_ << " 开始降落" << std::endl;
} else {
std::cout << "航班 " << flightId_ << " 降落请求被拒绝" << std::endl;
}
}
/**
* @brief 通知起飞完成
*/
virtual void notifyTakeoffComplete() {
status_ = FlightStatus::IN_AIR;
atc_->notifyTakeoffComplete(flightId_);
std::cout << "航班 " << flightId_ << " 起飞完成,正在飞行" << std::endl;
}
/**
* @brief 通知降落完成
*/
virtual void notifyLandingComplete() {
status_ = FlightStatus::ON_GROUND;
atc_->notifyLandingComplete(flightId_);
std::cout << "航班 " << flightId_ << " 降落完成" << std::endl;
}
};
/**
* @brief 具体飞机类
*/
class CommercialAircraft : public Aircraft {
public:
CommercialAircraft(const std::string& flightId,
std::shared_ptr<AirTrafficControl> atc)
: Aircraft(flightId, atc) {}
};
/**
* @brief 具体航空管制中介者
*/
class ConcreteATC : public AirTrafficControl {
private:
std::vector<std::shared_ptr<Aircraft>> aircrafts_;
int runwayInUse_; // 跑道使用状态
public:
ConcreteATC() : runwayInUse_(-1) {}
bool requestTakeoff(const std::string& flightId) override {
// 检查跑道是否被占用
if (runwayInUse_ != -1) {
std::cout << "塔台回复 " << flightId << ": 跑道忙碌,请等待" << std::endl;
return false;
}
// 分配跑道
for (size_t i = 0; i < aircrafts_.size(); ++i) {
if (aircrafts_[i]->getFlightId() == flightId) {
runwayInUse_ = i;
std::cout << "塔台回复 " << flightId << ": 允许起飞,使用跑道" << std::endl;
return true;
}
}
return false;
}
bool requestLanding(const std::string& flightId) override {
// 检查跑道是否被占用
if (runwayInUse_ != -1) {
std::cout << "塔台回复 " << flightId << ": 跑道忙碌,请盘旋等待" << std::endl;
return false;
}
// 分配跑道
for (size_t i = 0; i < aircrafts_.size(); ++i) {
if (aircrafts_[i]->getFlightId() == flightId) {
runwayInUse_ = i;
std::cout << "塔台回复 " << flightId << ": 允许降落,使用跑道" << std::endl;
return true;
}
}
return false;
}
void notifyTakeoffComplete(const std::string& flightId) override {
std::cout << "塔台确认: " << flightId << " 起飞完成,释放跑道" << std::endl;
runwayInUse_ = -1;
}
void notifyLandingComplete(const std::string& flightId) override {
std::cout << "塔台确认: " << flightId << " 降落完成,释放跑道" << std::endl;
runwayInUse_ = -1;
}
void registerAircraft(std::shared_ptr<Aircraft> aircraft) override {
aircrafts_.push_back(aircraft);
std::cout << "塔台: 注册航班 " << aircraft->getFlightId() << std::endl;
}
};
// 演示代码
int main() {
// 创建航空管制中心
auto atc = std::make_shared<ConcreteATC>();
// 创建飞机
auto flight1 = std::make_shared<CommercialAircraft>("CA123", atc);
auto flight2 = std::make_shared<CommercialAircraft>("UA456", atc);
auto flight3 = std::make_shared<CommercialAircraft>("DL789", atc);
// 注册飞机
atc->registerAircraft(flight1);
atc->registerAircraft(flight2);
atc->registerAircraft(flight3);
std::cout << "\n=== 航空管制演示 ===\n" << std::endl;
// 飞机操作
flight1->requestTakeoff(); // 应该成功
flight1->notifyTakeoffComplete();
flight2->requestTakeoff(); // 应该成功
flight3->requestLanding(); // 应该被拒绝(跑道忙碌)
flight2->notifyTakeoffComplete();
flight3->requestLanding(); // 现在应该成功
return 0;
}
3.3 案例三:UI组件交互系统
场景描述:
设计一个用户界面,包含多个交互组件(按钮、文本框、复选框等),这些组件之间的行为相互影响,但组件之间不直接通信,通过中介者协调。
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <functional>
// 前向声明
class UIComponent;
/**
* @brief UI中介者接口
*
* 协调UI组件之间的交互行为
*/
class UIMediator {
public:
virtual ~UIMediator() = default;
/**
* @brief 组件状态变化通知
*
* @param component 发生变化的组件
* @param event 事件类型
*/
virtual void notify(std::shared_ptr<UIComponent> component,
const std::string& event) = 0;
/**
* @brief 注册组件
*
* @param id 组件ID
* @param component 组件对象
*/
virtual void registerComponent(const std::string& id,
std::shared_ptr<UIComponent> component) = 0;
};
/**
* @brief UI组件抽象类
*/
class UIComponent {
protected:
std::string id_;
bool enabled_;
std::shared_ptr<UIMediator> mediator_;
public:
UIComponent(const std::string& id, std::shared_ptr<UIMediator> mediator)
: id_(id), enabled_(true), mediator_(mediator) {}
virtual ~UIComponent() = default;
std::string getId() const { return id_; }
bool isEnabled() const { return enabled_; }
virtual void setEnabled(bool enabled) {
enabled_ = enabled;
std::cout << "组件 " << id_ << " "
<< (enabled ? "启用" : "禁用") << std::endl;
}
/**
* @brief 触发组件行为
*/
virtual void trigger() {
if (enabled_) {
std::cout << "组件 " << id_ << " 被触发" << std::endl;
mediator_->notify(shared_from_this(), "triggered");
}
}
/**
* @brief 处理来自中介者的通知
*
* @param event 事件类型
* @param data 事件数据
*/
virtual void handleEvent(const std::string& event,
const std::string& data = "") = 0;
};
/**
* @brief 按钮组件
*/
class Button : public UIComponent, public std::enable_shared_from_this<Button> {
public:
Button(const std::string& id, std::shared_ptr<UIMediator> mediator)
: UIComponent(id, mediator) {}
void handleEvent(const std::string& event,
const std::string& data = "") override {
if (event == "disable_buttons") {
setEnabled(false);
} else if (event == "enable_buttons") {
setEnabled(true);
}
}
};
/**
* @brief 文本框组件
*/
class TextBox : public UIComponent, public std::enable_shared_from_this<TextBox> {
private:
std::string text_;
public:
TextBox(const std::string& id, std::shared_ptr<UIMediator> mediator)
: UIComponent(id, mediator), text_("") {}
void setText(const std::string& text) {
text_ = text;
std::cout << "文本框 " << id_ << " 内容设置为: " << text << std::endl;
mediator_->notify(shared_from_this(), "text_changed");
}
std::string getText() const { return text_; }
void handleEvent(const std::string& event,
const std::string& data = "") override {
if (event == "clear_text") {
setText("");
} else if (event == "disable_input") {
setEnabled(false);
}
}
};
/**
* @brief 复选框组件
*/
class CheckBox : public UIComponent, public std::enable_shared_from_this<CheckBox> {
private:
bool checked_;
public:
CheckBox(const std::string& id, std::shared_ptr<UIMediator> mediator)
: UIComponent(id, mediator), checked_(false) {}
void setChecked(bool checked) {
checked_ = checked;
std::cout << "复选框 " << id_ << " "
<< (checked ? "选中" : "取消选中") << std::endl;
mediator_->notify(shared_from_this(), "state_changed");
}
bool isChecked() const { return checked_; }
void trigger() override {
if (enabled_) {
setChecked(!checked_);
}
}
void handleEvent(const std::string& event,
const std::string& data = "") override {
// 复选框对其他组件事件不敏感
}
};
/**
* @brief 具体UI中介者
*/
class ConcreteUIMediator : public UIMediator {
private:
std::unordered_map<std::string, std::shared_ptr<UIComponent>> components_;
public:
void notify(std::shared_ptr<UIComponent> component,
const std::string& event) override {
std::string componentId = component->getId();
if (componentId == "submit_btn" && event == "triggered") {
// 提交按钮被点击:禁用所有按钮,清空文本框
for (auto& pair : components_) {
if (pair.first.find("btn") != std::string::npos) {
pair.second->handleEvent("disable_buttons");
} else if (pair.first.find("textbox") != std::string::npos) {
pair.second->handleEvent("clear_text");
}
}
} else if (componentId == "agree_checkbox" && event == "state_changed") {
// 同意复选框状态变化:启用/禁用提交按钮
auto checkbox = std::dynamic_pointer_cast<CheckBox>(component);
if (checkbox) {
auto submitBtn = components_["submit_btn"];
if (submitBtn) {
submitBtn->setEnabled(checkbox->isChecked());
}
}
} else if (componentId == "name_textbox" && event == "text_changed") {
// 姓名文本框内容变化:检查是否可以启用提交按钮
auto textbox = std::dynamic_pointer_cast<TextBox>(component);
if (textbox) {
auto agreeCheckbox = components_["agree_checkbox"];
auto submitBtn = components_["submit_btn"];
if (agreeCheckbox && submitBtn) {
bool agreed = std::dynamic_pointer_cast<CheckBox>(agreeCheckbox)->isChecked();
bool hasName = !textbox->getText().empty();
submitBtn->setEnabled(agreed && hasName);
}
}
}
}
void registerComponent(const std::string& id,
std::shared_ptr<UIComponent> component) override {
components_[id] = component;
std::cout << "注册UI组件: " << id << std::endl;
}
};
// 演示代码
int main() {
// 创建UI中介者
auto mediator = std::make_shared<ConcreteUIMediator>();
// 创建UI组件
auto nameTextbox = std::make_shared<TextBox>("name_textbox", mediator);
auto agreeCheckbox = std::make_shared<CheckBox>("agree_checkbox", mediator);
auto submitButton = std::make_shared<Button>("submit_btn", mediator);
// 注册组件
mediator->registerComponent("name_textbox", nameTextbox);
mediator->registerComponent("agree_checkbox", agreeCheckbox);
mediator->registerComponent("submit_btn", submitButton);
std::cout << "\n=== UI交互演示 ===\n" << std::endl;
// 模拟用户交互
std::cout << "1. 初始状态 - 提交按钮应该被禁用" << std::endl;
std::cout << "提交按钮状态: " << (submitButton->isEnabled() ? "启用" : "禁用") << std::endl;
std::cout << "\n2. 输入姓名 - 提交按钮仍然被禁用(未同意条款)" << std::endl;
nameTextbox->setText("张三");
std::cout << "提交按钮状态: " << (submitButton->isEnabled() ? "启用" : "禁用") << std::endl;
std::cout << "\n3. 同意条款 - 提交按钮应该启用" << std::endl;
agreeCheckbox->trigger(); // 选中复选框
std::cout << "提交按钮状态: " << (submitButton->isEnabled() ? "启用" : "禁用") << std::endl;
std::cout << "\n4. 点击提交按钮 - 所有按钮被禁用,文本框被清空" << std::endl;
submitButton->trigger();
return 0;
}
4. 编译与运行
4.1 Makefile范例
# 编译器设置
CXX := g++
CXXFLAGS := -std=c++17 -Wall -Wextra -O2
TARGET := mediator_demo
SRCS := chat_mediator.cpp aircraft_mediator.cpp ui_mediator.cpp
# 默认目标
all: $(TARGET)
# 链接目标文件
$(TARGET): $(SRCS:.cpp=.o)
$(CXX) $(CXXFLAGS) -o $@ $^
# 编译源文件
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
# 清理生成文件
clean:
rm -f *.o $(TARGET)
# 运行演示
run: $(TARGET)
./$(TARGET)
# 调试编译
debug: CXXFLAGS += -g -DDEBUG
debug: $(TARGET)
.PHONY: all clean run debug
4.2 编译方法
# 1. 基础编译
make
# 2. 调试模式编译
make debug
# 3. 单独编译聊天室案例
g++ -std=c++17 -o chat_demo chat_mediator.cpp
# 4. 清理编译文件
make clean
4.3 运行结果解读
聊天室系统输出示例:
=== 聊天开始 ===
Alice 发送广播: 大家好!
=== 聊天室广播 === (Alice): 大家好!
Bob 收到来自 Alice 的消息: 大家好!
Charlie 收到来自 Alice 的消息: 大家好!
Alice 私聊 Bob: 嘿,Bob,有个秘密要告诉你
=== 私聊消息 === [Alice -> Bob]: 嘿,Bob,有个秘密要告诉你
Bob 收到来自 Alice 的消息: [私聊] 嘿,Bob,有个秘密要告诉你
结果分析:
- 消息通过中介者正确路由到目标用户
- 广播消息发送给除发送者外的所有用户
- 私聊消息只发送给指定用户
- 系统消息(用户加入/离开)自动广播
5. 模式优势与局限性总结
5.1 优势对比
方面 | 使用中介者模式前 | 使用中介者模式后 |
---|---|---|
耦合度 | 对象间直接引用,网状耦合 | 通过中介者通信,星状耦合 |
可维护性 | 修改一个对象影响多个对象 | 交互逻辑集中,易于维护 |
扩展性 | 新增对象需要修改多个现有对象 | 新增对象只需注册到中介者 |
复用性 | 对象因相互引用难以单独复用 | 对象可以独立复用 |
5.2 适用场景建议
推荐使用中介者模式:
- 🎯 对象间交互复杂且频繁
- 🎯 需要集中管理对象间关系
- 🎯 系统需要良好的扩展性和维护性
不推荐使用中介者模式:
- ⚠️ 对象间交互简单直接
- ⚠️ 性能要求极高的场景
- ⚠️ 中介者可能成为系统瓶颈
中介者模式通过引入协调层,成功地将复杂的网状交互转化为清晰的星状结构,是现代软件设计中解决对象通信复杂性的重要工具。