18. 中介者模式(Mediator Pattern)
分类 : 行为型模式
热门度 : ★★★☆☆
难度: ★★★☆☆
📖 概念
中介者模式定义一个中介对象来封装一组对象之间的交互,使各对象不需要显式地相互引用,从而降低耦合度。
🎯 意图
将多对多的网状交互转换为一对多的星型交互,所有同事对象通过中介者通信。
🔑 关键角色
| 角色 | 说明 |
|---|---|
| IMediator(中介者接口) | 定义通信接口 |
| ConcreteMediator(具体中介者) | 协调各同事对象的交互 |
| Colleague(同事对象) | 通过中介者与其他同事通信 |
⚠️ 注意事项
- 中介者可能变得过于复杂(上帝对象)
- 适合交互关系复杂的场景,简单场景不必使用
- C# 中可结合事件机制实现松耦合
🔄 实现流程
1. 定义中介者接口
2. 创建具体中介者,持有所有同事引用
3. 同事对象持有中介者引用
4. 同事间通过中介者转发消息
💡 常见使用场景
场景1: 聊天室消息转发
csharp
// 中介者接口
public interface IChatMediator
{
void SendMessage(string message, User sender);
void RegisterUser(User user);
}
// 同事基类
public abstract class User
{
protected IChatMediator _mediator;
public string Name { get; set; }
protected User(IChatMediator mediator, string name)
{ _mediator = mediator; Name = name; }
public abstract void Send(string message);
public abstract void Receive(string message);
}
// 具体中介者 - 聊天室
public class ChatRoom : IChatMediator
{
private Dictionary<string, User> _users = new();
public void RegisterUser(User user) => _users[user.Name] = user;
public void SendMessage(string message, User sender)
{
foreach (var user in _users.Values)
if (user != sender) user.Receive($"[{sender.Name}]: {message}");
}
}
// 具体同事
public class ChatUser : User
{
public ChatUser(IChatMediator mediator, string name) : base(mediator, name) { }
public override void Send(string message) => _mediator.SendMessage(message, this);
public override void Receive(string message) => Console.WriteLine($"{Name} 收到: {message}");
}
// 使用
var chatRoom = new ChatRoom();
var alice = new ChatUser(chatRoom, "Alice");
var bob = new ChatUser(chatRoom, "Bob");
var charlie = new ChatUser(chatRoom, "Charlie");
chatRoom.RegisterUser(alice);
chatRoom.RegisterUser(bob);
chatRoom.RegisterUser(charlie);
alice.Send("大家好!"); // Bob 和 Charlie 都收到
场景2: 表单字段联动
csharp
// 中介者接口
public interface IFormMediator
{
void ValueChanged(string fieldName, string value);
}
// 具体中介者 - 注册表单
public class RegistrationFormMediator : IFormMediator
{
private CountryDropdown _country;
private CityDropdown _city;
private PhoneInput _phone;
private SubmitButton _submit;
public RegistrationFormMediator()
{
_country = new CountryDropdown(this);
_city = new CityDropdown(this);
_phone = new PhoneInput(this);
_submit = new SubmitButton(this);
}
public void ValueChanged(string fieldName, string value)
{
switch (fieldName)
{
case "country":
Console.WriteLine($"[中介者] 国家变更为 {value},更新城市列表和区号");
_city.UpdateCities(value);
_phone.UpdateCountryCode(value);
break;
case "city":
Console.WriteLine($"[中介者] 城市变更为 {value},检查表单完整性");
break;
case "phone":
Console.WriteLine($"[中介者] 电话变更,验证格式");
_submit.SetEnabled(!string.IsNullOrEmpty(value));
break;
}
}
public void Simulate() { _country.Select("中国"); _phone.SetPhone("13800138000"); }
}
// 同事类
public class CountryDropdown
{
private IFormMediator _mediator;
public CountryDropdown(IFormMediator mediator) { _mediator = mediator; }
public void Select(string country) { Console.WriteLine($"选择国家: {country}"); _mediator.ValueChanged("country", country); }
}
public class CityDropdown
{
private IFormMediator _mediator;
public CityDropdown(IFormMediator mediator) { _mediator = mediator; }
public void UpdateCities(string country) => Console.WriteLine($"更新城市列表: {country} 的城市");
}
public class PhoneInput
{
private IFormMediator _mediator;
public PhoneInput(IFormMediator mediator) { _mediator = mediator; }
public void SetPhone(string phone) { Console.WriteLine($"输入电话: {phone}"); _mediator.ValueChanged("phone", phone); }
public void UpdateCountryCode(string country) => Console.WriteLine($"更新区号: {country}");
}
public class SubmitButton
{
private IFormMediator _mediator;
public SubmitButton(IFormMediator mediator) { _mediator = mediator; }
public void SetEnabled(bool enabled) => Console.WriteLine($"提交按钮: {(enabled ? "可用" : "禁用")}");
}
// 使用
var form = new RegistrationFormMediator();
form.Simulate();
场景3: 智能家居设备协调
csharp
public interface IHomeMediator
{
void Notify(string source, string @event);
}
public class SmartHomeHub : IHomeMediator
{
private Dictionary<string, Action<string>> _handlers = new();
public void Register(string device, Action<string> handler) => _handlers[device] = handler;
public void Notify(string source, string @event)
{
Console.WriteLine($"[中枢] {source} 触发: {@event}");
foreach (var handler in _handlers)
if (handler.Key != source) handler.Value($"{source}:{@event}");
}
}
public class SmartLight
{
private string _name;
private IHomeMediator _mediator;
public SmartLight(string name, IHomeMediator mediator) { _name = name; _mediator = mediator; }
public void TurnOn() { Console.WriteLine($"{_name} 灯打开"); _mediator.Notify(_name, "on"); }
public void OnEvent(string e) => Console.WriteLine($"{_name} 收到事件: {e}");
}
public class SmartCurtain
{
private string _name;
private IHomeMediator _mediator;
public SmartCurtain(string name, IHomeMediator mediator) { _name = name; _mediator = mediator; }
public void Open() { Console.WriteLine($"{_name} 窗帘打开"); _mediator.Notify(_name, "open"); }
public void OnEvent(string e) => Console.WriteLine($"{_name} 收到事件: {e}");
}
// 使用
var hub = new SmartHomeHub();
var light = new SmartLight("客厅灯", hub);
var curtain = new SmartCurtain("客厅窗帘", hub);
hub.Register("客厅灯", light.OnEvent);
hub.Register("客厅窗帘", curtain.OnEvent);
light.TurnOn(); // 窗帘也会收到通知
✅ 优点
- 降低同事对象之间的耦合
- 将多对多交互转为一对多
- 符合迪米特原则
❌ 缺点
- 中介者可能变得过于复杂
- 中介者承担过多职责时难以维护
📊 与其他模式对比
| 模式 | 区别 |
|---|---|
| 观察者模式 | 观察者是一对多广播,中介者是多对多协调 |
| 外观模式 | 外观简化子系统接口,中介者协调对象交互 |
| 命令模式 | 命令封装请求,中介者协调通信 |