概述定义
定义:
用一个中介对象来封装一系列对象之间的交互,使对象之间不需要显式地相互引用,从而降低耦合度,并且可以独立地改变它们之间的交互。它是一种行为型模式,常用于简化复杂系统中对象间的通信。
目的:
中介者模式通过引入一个“中介者”对象来集中管理多个对象之间的交互逻辑,避免对象之间形成复杂的网状依赖关系,从而降低系统的耦合性,提升可维护性和可扩展性。
关键点:
解耦对象间的直接联系:各个对象不再互相调用,而是统一通过中介者来传递消息,彼此之间“不认识”也能协作。
交互逻辑集中管理:所有对象之间的协作规则都收拢到中介者里,改逻辑只需要动一个地方,维护起来省心。
降低系统耦合度:每个组件只依赖中介者,不需要知道其他组件的存在,改动一个模块不容易牵连别人。
提升复用性:因为组件不和其他具体对象绑定,拿出来换个场景、换套交互规则,基本不用大改。
符合迪米特法则:一个对象只和“直接朋友”(这里就是中介者)打交道,不跟系统里各种“陌生人”扯上关系,结构更清晰、更稳定。
应用场景
GUI界面联动:比如一个对话框里,选了下拉框某一项,按钮要变灰、文本框要清空。这些控件彼此不直接调用,而是由窗口或控制器(中介者)统一监听和协调。
多人游戏逻辑:玩家操作、NPC行为、道具掉落、地图事件等,通常不互相直接通知,而是发给游戏服务器(作为中介者),由它来判断是否合法、触发什么后续动作。
聊天室系统:用户发消息不是直接推给其他用户,而是先发到服务器,服务器再广播给房间里的其他人。这样用户之间完全解耦,加人、踢人、禁言都好处理。
航空管制:飞机不会互相喊话协调航线,所有通信都通过塔台。塔台掌握全局状态,统一指挥起降和避让,避免混乱。
微服务架构中的协调层:比如用 API 网关统一路由,或通过事件总线(如 Kafka)传递消息,服务只和中间件打交道,不直接依赖彼此,便于独立部署和演进。
优缺点
优点
对象之间不再拉扯:以前一个类要持有好几个其他类的引用,改一处可能牵一串。现在大家只认中介者,依赖关系清爽。
交互逻辑收拢到一处:像界面控件联动、服务间协作这些复杂流程,全集中在中介者里处理。以后要调整规则,不用到处翻代码,改一个地方就行。
组件更容易复用:因为对象不关心“谁在和我配合”,只管做好自己的事。下次换个场景,只要接上新的中介者,基本不用动它。
扩展更轻松:比如要加一种新的交互方式,通常只需改中介者或加个新方法,原来的组件完全不用动,符合开闭原则。
对象变得更专注:每个类只负责自己的核心功能,不用掺和“怎么通知别人“,“什么时候触发谁”这类杂事,职责单一,代码也更干净。
说白了,中介者就像团队里的协调人——大家专心干活,沟通的事交给他,效率高还不容易乱。
缺点
中介者可能过于复杂一开始只是协调两三个对象,后来功能越加越多,所有交互逻辑都塞进去,最后变成一个又大又杂的“上帝类”,维护起来复杂无比。
可能拖慢系统:所有通信都得绕道中介者,尤其在高频调用或实时性要求高的场景里,这个中间层反而成了瓶颈。
调试不太直观:比如某个按钮点下去没反应,你得先看它通知了中介者,再看中介者怎么分发,中间可能还夹着条件判断,调用链一长,追踪起来费劲。
过度设计:如果只是两个对象简单互动,硬套中介者反而绕远了。代码多了,理解成本也高了,不如直接调用来得干脆。
测试麻烦:中介者通常要和多个组件打交道,写单元测试时得 mock 一堆依赖,准备数据繁琐,维护测试用例也累。
实现示例
示例背景:teld用户充电系统
参与者:用户(User)
中介者:充电调度中心
功能:用户发送充电消息,调度中心调度充电
中介者接口(IChargingHub)
public interface IChargingHub
{
void RegisterCharger(ICharger charger);
void StartCharge(ITeldUser user, string chargerId);
void StopCharge(ITeldUser user, string chargerId);
}用户端行为接口
public interface ITeldUser
{
string UserId { get; }
void RequestStartCharge(string chargerId);
void RequestStopCharge(string chargerId);
}充电桩行为接口
public interface ICharger
{
string ChargerId { get; }
void StartCharging(string userId);
void StopCharging(string userId);
}调度中心
public class TeldChargingHub : IChargingHub
{
private readonly Dictionary _chargers = new();
private readonly Dictionary _userChargerMap = new();
public void RegisterCharger(ICharger charger)
{
_chargers[charger.ChargerId] = charger;
}
public void StartCharge(ITeldUser user, string chargerId)
{
if (!_chargers.TryGetValue(chargerId, out var charger))
{
Console.WriteLine($"[调度中心] 充电桩 {chargerId} 不存在");
return;
}
// 简单控制:直接启动
_userChargerMap[user.UserId] = chargerId;
charger.StartCharging(user.UserId);
}
public void StopCharge(ITeldUser user, string chargerId)
{
if (_userChargerMap.TryGetValue(user.UserId, out var assignedCharger) && assignedCharger == chargerId)
{
_chargers[chargerId].StopCharging(user.UserId);
_userChargerMap.Remove(user.UserId);
}
else
{
Console.WriteLine($"[调度中心] 用户 {user.UserId} 未使用充电桩 {chargerId},无法停止");
}
}
}充电桩实现
public class TeldCharger : ICharger
{
public string ChargerId { get; }
private readonly IChargingHub _hub;
public TeldCharger(string id, IChargingHub hub)
{
ChargerId = id;
_hub = hub;
}
public void StartCharging(string userId)
{
Console.WriteLine($"[充电桩 {ChargerId}] 开始为用户 {userId} 充电");
}
public void StopCharging(string userId)
{
Console.WriteLine($"[充电桩 {ChargerId}] 停止为用户 {userId} 充电");
}
}用户实现
public class TeldMobileApp : ITeldUser
{
public string UserId { get; }
private readonly IChargingHub _hub;
public TeldMobileApp(string userId, IChargingHub hub)
{
UserId = userId;
_hub = hub;
}
public void RequestStartCharge(string chargerId)
{
Console.WriteLine($"[用户 {UserId}] 请求启动充电桩 {chargerId}");
_hub.StartCharge(this, chargerId);
}
public void RequestStopCharge(string chargerId)
{
Console.WriteLine($"[用户 {UserId}] 请求停止充电桩 {chargerId}");
_hub.StopCharge(this, chargerId);
}
}使用示例
class Program
{
static void Main()
{
// 创建中介者
IChargingHub hub = new TeldChargingHub();
// 创建并注册充电桩
ICharger c1 = new TeldCharger("CD001", hub);
ICharger c2 = new TeldCharger("CD002", hub);
hub.RegisterCharger(c1);
hub.RegisterCharger(c2);
// 创建用户
ITeldUser userA = new TeldMobileApp("U1001", hub);
ITeldUser userB = new TeldMobileApp("U1002", hub);
// 操作流程
userA.RequestStartCharge("CD001");
userB.RequestStartCharge("CD002");
userA.RequestStopCharge("CD001");
}
}总结思考
核心思想:把原本乱成蜘蛛网的对象交互,收拢到一个“协调人”手里。大家不再互相直接调用,而是通过这个中介者沟通,结构一下子清晰了。
实现方式:先定个中介者接口,再写具体实现;各个“同事”对象只持有中介者的引用,需要协作时就发消息给它,由它决定怎么处理、通知谁。
应用价值:这种设计特别适合那些组件多、联动复杂的场景,比如 GUI 界面里一堆控件互相影响,聊天室里用户动态广播,或者游戏里角色、道具、地图之间的状态同步。
注意事项:一旦发现它管得太多、代码膨胀,就得考虑拆分——比如按功能划分子中介者,或者引入事件机制把部分逻辑解耦出去。