实用指南:中介者模式:解耦对象交互的艺术

行为型设计模式之中介者模式

1. 中介者模式简介

中介者模式(Mediator Pattern)是一种行为型设计模式,它用一个中介对象来封装一系列对象之间的交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

在软件系统中,随着类的不断增加,类与类之间的依赖关系会变得非常复杂,形成一个网状结构,这种情况被称为"类爆炸"。中介者模式的主要目的就是将这种网状依赖结构转变为星型结构,从而降低系统的复杂度。

中介者模式的核心思想是:将相关对象之间的通信委托给中介者对象处理,对象之间不再直接通信,而是通过中介者来协调它们的交互。这样,当一个对象发生变化时,只需要通知中介者,由中介者通知相关的其他对象做出响应。

2. 中介者模式的结构

中介者模式主要包含以下几个角色:

«interface»
Mediator
Send(message, colleague)
ConcreteMediator
colleagues
Send(message, colleague)
AddColleague(colleague)
«abstract»
Colleague
mediator
SetMediator(mediator)
Send(message)
Receive(message)
ConcreteColleague1
+Send(message)
+Receive(message)
ConcreteColleague2
Send(message)
Receive(message)
  1. Mediator(中介者):定义了一个接口,用于各同事(Colleague)对象之间的通信。
  2. ConcreteMediator(具体中介者):实现中介者接口,协调各同事对象之间的交互关系。了解并维护着各个同事对象。
  3. Colleague(同事):定义一个抽象类,维护一个指向中介者的引用,每个同事都知道它的中介者对象。
  4. ConcreteColleague(具体同事):实现抽象同事类,通过中介者与其他同事通信。

3. 中介者模式的实现(C#)

下面通过几个不同的C#实现来展示中介者模式。

3.1 基本实现

首先,我们创建一个简单的聊天室系统,展示中介者模式的基本实现:

using System;
using System.Collections.Generic;
// 中介者接口
public interface IChatMediator
{
void SendMessage(string msg, User user); // 发送消息
void AddUser(User user);                 // 添加用户
}
// 抽象用户类
public abstract class User
{
protected IChatMediator mediator; // 对中介者的引用
protected string name;            // 用户名
// 构造函数
public User(IChatMediator mediator, string name)
{
this.mediator = mediator;
this.name = name;
}
// 发送消息
public abstract void Send(string msg);
// 接收消息
public abstract void Receive(string msg);
}
// 具体中介者:聊天室
public class ChatRoom : IChatMediator
{
private List<User> users; // 用户列表
  // 构造函数
  public ChatRoom()
  {
  users = new List<User>();
    }
    // 添加用户到聊天室
    public void AddUser(User user)
    {
    users.Add(user);
    }
    // 将消息发送给所有用户,除了发送者
    public void SendMessage(string msg, User user)
    {
    foreach (var u in users)
    {
    // 不发送给自己
    if (u != user)
    {
    u.Receive(msg);
    }
    }
    }
    }
    // 具体用户:普通用户
    public class NormalUser : User
    {
    // 构造函数
    public NormalUser(IChatMediator mediator, string name) : base(mediator, name)
    {
    }
    // 发送消息
    public override void Send(string msg)
    {
    Console.WriteLine($"{name} 发送消息: {msg}");
    mediator.SendMessage(msg, this);
    }
    // 接收消息
    public override void Receive(string msg)
    {
    Console.WriteLine($"{name} 收到消息: {msg}");
    }
    }
    // 具体用户:管理员用户
    public class AdminUser : User
    {
    // 构造函数
    public AdminUser(IChatMediator mediator, string name) : base(mediator, name)
    {
    }
    // 发送消息(带有管理员标记)
    public override void Send(string msg)
    {
    Console.WriteLine($"管理员 {name} 发送消息: {msg}");
    mediator.SendMessage($"[管理员消息] {msg}", this);
    }
    // 接收消息
    public override void Receive(string msg)
    {
    Console.WriteLine($"管理员 {name} 收到消息: {msg}");
    }
    }
    // 客户端代码
    public class Program
    {
    static void Main(string[] args)
    {
    // 创建中介者:聊天室
    IChatMediator chatroom = new ChatRoom();
    // 创建用户
    User user1 = new NormalUser(chatroom, "张三");
    User user2 = new NormalUser(chatroom, "李四");
    User user3 = new NormalUser(chatroom, "王五");
    User admin = new AdminUser(chatroom, "管理员");
    // 将用户添加到聊天室
    chatroom.AddUser(user1);
    chatroom.AddUser(user2);
    chatroom.AddUser(user3);
    chatroom.AddUser(admin);
    // 用户发送消息
    user1.Send("大家好!");
    Console.WriteLine();
    admin.Send("请注意聊天室规则。");
    Console.WriteLine();
    user2.Send("收到,谢谢提醒!");
    }
    }

3.2 使用事件和委托的实现

在C#中,我们可以利用事件和委托机制来实现中介者模式,使代码更加符合C#的风格:

using System;
using System.Collections.Generic;
// 消息事件参数
public class MessageEventArgs : EventArgs
{
public string Message { get; }  // 消息内容
public string SenderName { get; } // 发送者名称
public MessageEventArgs(string message, string senderName)
{
Message = message;
SenderName = senderName;
}
}
// 中介者:聊天服务
public class ChatService
{
// 消息发送事件
public event EventHandler<MessageEventArgs> MessageSent;
  // 用户字典,键为用户名
  private Dictionary<string, IChatClient> clients = new Dictionary<string, IChatClient>();
    // 注册客户端
    public void RegisterClient(IChatClient client)
    {
    if (!clients.ContainsKey(client.Name))
    {
    clients.Add(client.Name, client);
    // 订阅客户端的发送消息事件
    client.SendMessage += OnClientSendMessage;
    Console.WriteLine($"客户端 {client.Name} 已注册");
    }
    }
    // 注销客户端
    public void UnregisterClient(IChatClient client)
    {
    if (clients.ContainsKey(client.Name))
    {
    clients.Remove(client.Name);
    // 取消订阅客户端的发送消息事件
    client.SendMessage -= OnClientSendMessage;
    Console.WriteLine($"客户端 {client.Name} 已注销");
    }
    }
    // 处理客户端发送消息事件
    private void OnClientSendMessage(object sender, MessageEventArgs e)
    {
    // 触发消息发送事件,通知所有客户端
    MessageSent?.Invoke(this, e);
    }
    // 发送私信
    public void SendPrivateMessage(string message, string senderName, string receiverName)
    {
    if (clients.ContainsKey(receiverName))
    {
    // 直接向特定客户端发送消息
    clients[receiverName].ReceiveMessage(message, senderName, true);
    }
    }
    }
    // 聊天客户端接口
    public interface IChatClient
    {
    string Name { get; } // 客户端名称
    event EventHandler<MessageEventArgs> SendMessage; // 发送消息事件
      void ReceiveMessage(string message, string senderName, bool isPrivate = false); // 接收消息
      }
      // 具体聊天客户端
      public class ChatClient : IChatClient
      {
      private ChatService chatService; // 聊天服务(中介者)
      public string Name { get; private set; } // 客户端名称
      // 发送消息事件
      public event EventHandler<MessageEventArgs> SendMessage;
        // 构造函数
        public ChatClient(string name, ChatService chatService)
        {
        Name = name;
        this.chatService = chatService;
        // 订阅中介者的消息发送事件
        chatService.MessageSent += OnMessageReceived;
        // 注册到中介者
        chatService.RegisterClient(this);
        }
        // 处理收到的消息
        private void OnMessageReceived(object sender, MessageEventArgs e)
        {
        // 不接收自己发送的消息
        if (e.SenderName != Name)
        {
        Console.WriteLine($"{Name} 收到来自 {e.SenderName} 的消息: {e.Message}");
        }
        }
        // 向所有客户端发送消息
        public void BroadcastMessage(string message)
        {
        Console.WriteLine($"{Name} 发送广播消息: {message}");
        // 触发发送消息事件,通知中介者
        SendMessage?.Invoke(this, new MessageEventArgs(message, Name));
        }
        // 发送私信
        public void SendPrivateMessage(string message, string receiverName)
        {
        Console.WriteLine($"{Name}{receiverName} 发送私信: {message}");
        chatService.SendPrivateMessage(message, Name, receiverName);
        }
        // 接收消息
        public void ReceiveMessage(string message, string senderName, bool isPrivate = false)
        {
        string messageType = isPrivate ? "私信" : "消息";
        Console.WriteLine($"{Name} 收到来自 {senderName}{messageType}: {message}");
        }
        // 析构函数,注销客户端
        ~ChatClient()
        {
        chatService.MessageSent -= OnMessageReceived;
        chatService.UnregisterClient(this);
        }
        }
        // 客户端代码
        public class Program
        {
        static void Main(string[] args)
        {
        // 创建中介者:聊天服务
        ChatService chatService = new ChatService();
        // 创建聊天客户端
        ChatClient client1 = new ChatClient("张三", chatService);
        ChatClient client2 = new ChatClient("李四", chatService);
        ChatClient client3 = new ChatClient("王五", chatService);
        // 客户端发送广播消息
        client1.BroadcastMessage("大家好!");
        Console.WriteLine();
        // 客户端发送私信
        client2.SendPrivateMessage("你好,有时间聊聊吗?", "张三");
        Console.WriteLine();
        client3.BroadcastMessage("今天天气真好!");
        }
        }

3.3 GUI控件交互实现

以下是一个模拟GUI控件交互的中介者模式实现,展示了如何使用中介者模式来协调表单控件之间的交互:

using System;
using System.Collections.Generic;
// 抽象中介者
public interface IDialogMediator
{
void ControlChanged(Control control); // 当控件状态改变时调用
}
// 抽象控件类
public abstract class Control
{
protected IDialogMediator mediator; // 对中介者的引用
protected string name;              // 控件名称
// 构造函数
public Control(IDialogMediator mediator, string name)
{
this.mediator = mediator;
this.name = name;
}
// 控件名称属性
public string Name => name;
// 当控件状态改变时,通知中介者
public void Changed()
{
mediator.ControlChanged(this);
}
// 具体控件需要实现的事件处理方法
public abstract void HandleEvent();
}
// 具体控件:按钮
public class Button : Control
{
private bool enabled; // 按钮是否启用
// 构造函数
public Button(IDialogMediator mediator, string name) : base(mediator, name)
{
enabled = true;
}
// 启用/禁用按钮
public void SetEnabled(bool enabled)
{
this.enabled = enabled;
Console.WriteLine($"按钮 '{name}' {(enabled ? "已启用" : "已禁用")}");
}
// 点击按钮
public void Click()
{
if (enabled)
{
Console.WriteLine($"按钮 '{name}' 被点击");
Changed(); // 通知中介者
}
else
{
Console.WriteLine($"按钮 '{name}' 已禁用,无法点击");
}
}
// 处理事件
public override void HandleEvent()
{
Console.WriteLine($"按钮 '{name}' 处理事件");
}
}
// 具体控件:文本框
public class TextBox : Control
{
private string text; // 文本内容
// 构造函数
public TextBox(IDialogMediator mediator, string name) : base(mediator, name)
{
text = "";
}
// 获取文本内容
public string GetText()
{
return text;
}
// 设置文本内容
public void SetText(string text)
{
this.text = text;
Console.WriteLine($"文本框 '{name}' 的内容设置为: {text}");
Changed(); // 通知中介者
}
// 处理事件
public override void HandleEvent()
{
Console.WriteLine($"文本框 '{name}' 处理事件");
}
}
// 具体控件:复选框
public class CheckBox : Control
{
private bool checked_; // 是否选中
// 构造函数
public CheckBox(IDialogMediator mediator, string name) : base(mediator, name)
{
checked_ = false;
}
// 是否选中
public bool IsChecked()
{
return checked_;
}
// 设置选中状态
public void SetChecked(bool checked_)
{
this.checked_ = checked_;
Console.WriteLine($"复选框 '{name}' {(checked_ ? "已选中" : "已取消选中")}");
Changed(); // 通知中介者
}
// 处理事件
public override void HandleEvent()
{
Console.WriteLine($"复选框 '{name}' 处理事件");
}
}
// 具体中介者:用户注册对话框
public class UserRegistrationDialog : IDialogMediator
{
// 对话框中的控件
private TextBox usernameTextBox;
private TextBox passwordTextBox;
private Button okButton;
private Button cancelButton;
private CheckBox agreeTermsCheckBox;
// 初始化对话框及其控件
public void InitComponents()
{
usernameTextBox = new TextBox(this, "用户名");
passwordTextBox = new TextBox(this, "密码");
okButton = new Button(this, "确定");
cancelButton = new Button(this, "取消");
agreeTermsCheckBox = new CheckBox(this, "同意条款");
// 初始状态下,确定按钮禁用
okButton.SetEnabled(false);
}
// 获取控件引用
public TextBox GetUsernameTextBox() => usernameTextBox;
public TextBox GetPasswordTextBox() => passwordTextBox;
public Button GetOkButton() => okButton;
public Button GetCancelButton() => cancelButton;
public CheckBox GetAgreeTermsCheckBox() => agreeTermsCheckBox;
// 实现中介者接口方法,当控件状态改变时调用
public void ControlChanged(Control control)
{
// 根据不同控件的状态变化,协调其他控件的行为
if (control == usernameTextBox || control == passwordTextBox || control == agreeTermsCheckBox)
{
// 验证表单是否可以提交
ValidateForm();
}
else if (control == okButton)
{
// 处理确定按钮点击事件
SubmitForm();
}
else if (control == cancelButton)
{
// 处理取消按钮点击事件
CancelForm();
}
}
// 验证表单
private void ValidateForm()
{
// 检查用户名和密码是否已填写,以及是否同意条款
bool isValid = !string.IsNullOrEmpty(usernameTextBox.GetText()) &&
!string.IsNullOrEmpty(passwordTextBox.GetText()) &&
agreeTermsCheckBox.IsChecked();
// 根据验证结果启用或禁用确定按钮
okButton.SetEnabled(isValid);
Console.WriteLine($"表单验证: {(isValid ? "有效" : "无效")}");
}
// 提交表单
private void SubmitForm()
{
Console.WriteLine("表单提交成功!");
Console.WriteLine($"用户名: {usernameTextBox.GetText()}");
Console.WriteLine($"密码: {new string('*', passwordTextBox.GetText().Length)}");
}
// 取消表单
private void CancelForm()
{
Console.WriteLine("表单已取消");
// 清空所有字段
usernameTextBox.SetText("");
passwordTextBox.SetText("");
agreeTermsCheckBox.SetChecked(false);
}
}
// 客户端代码
public class Program
{
static void Main(string[] args)
{
// 创建中介者:用户注册对话框
UserRegistrationDialog dialog = new UserRegistrationDialog();
dialog.InitComponents();
// 获取对话框中的控件
TextBox usernameTextBox = dialog.GetUsernameTextBox();
TextBox passwordTextBox = dialog.GetPasswordTextBox();
CheckBox agreeTermsCheckBox = dialog.GetAgreeTermsCheckBox();
Button okButton = dialog.GetOkButton();
Button cancelButton = dialog.GetCancelButton();
// 模拟用户操作
Console.WriteLine("开始用户注册流程:");
// 设置用户名
usernameTextBox.SetText("john_doe");
// 设置密码
passwordTextBox.SetText("secure123");
// 勾选同意条款(此时确定按钮应该被启用)
agreeTermsCheckBox.SetChecked(true);
// 点击确定按钮(提交表单)
okButton.Click();
Console.WriteLine("\n开始新的注册流程:");
// 点击取消按钮(清空表单)
cancelButton.Click();
// 尝试点击确定按钮(由于表单已清空,按钮应该是禁用的)
okButton.Click();
}
}

4. 中介者模式与观察者模式的区别

中介者模式和观察者模式都是处理对象间通信的设计模式,但它们有一些关键区别:

中介者模式
观察者模式
中介者
同事1
同事2
同事3
观察者1
主题
观察者2
观察者3
  1. 通信方式

    • 观察者模式:是一对多的关系,主题(Subject)直接通知所有观察者(Observer)。
    • 中介者模式:是多对多的关系,各同事(Colleague)对象通过中介者(Mediator)间接通信。
  2. 依赖关系

    • 观察者模式:观察者依赖于主题,主题不依赖于观察者。
    • 中介者模式:同事对象与中介者相互依赖。
  3. 通信流向

    • 观察者模式:通信是单向的,从主题到观察者。
    • 中介者模式:通信是双向的,同事对象既可以发送消息也可以接收消息。
  4. 目的

    • 观察者模式:主要目的是在状态变化时通知依赖对象。
    • 中介者模式:主要目的是减少对象之间的直接依赖关系。

下面是一个对比表,展示两种模式在不同方面的区别:

«comparison»
PatternComparison
ObserverPattern
通信关系: 一对多
依赖方向: 单向
通信流向: 单向
主要目的: 状态变化通知
典型场景: 事件处理系统
MediatorPattern
通信关系: 多对多
依赖方向: 双向
通信流向: 双向
主要目的: 减少直接依赖
典型场景: 复杂UI交互

5. 中介者模式的应用场景

中介者模式适用于以下场景:

  1. 复杂的UI交互:如对话框中各控件之间的交互。例如,当用户在一个表单中勾选某个复选框时,其他的输入框可能被启用或禁用。

  2. 聊天应用:聊天室中的用户之间不直接通信,而是通过聊天服务器(中介者)来转发消息。

  3. 飞行控制系统:机场的塔台控制(中介者)负责协调各飞机(同事)的起飞和降落。

  4. 多人游戏:游戏服务器(中介者)协调各玩家(同事)之间的交互。

  5. 协同编辑软件:如在线文档编辑工具,其中所有用户的编辑操作都通过中央服务器(中介者)进行协调。

  6. MVC/MVP架构:Controller/Presenter作为中介者,协调Model和View之间的交互。

示例场景:航空交通管制系统

以下是一个航空交通管制系统的简化实现,展示中介者模式在该场景中的应用:

using System;
using System.Collections.Generic;
// 中介者接口:航空交通管制
public interface IAirTrafficControl
{
void RegisterAircraft(Aircraft aircraft);           // 注册飞机
void SendMessage(string message, Aircraft sender);  // 发送消息
void RequestLanding(Aircraft aircraft);             // 请求降落
void RequestTakeoff(Aircraft aircraft);             // 请求起飞
}
// 抽象同事类:飞机
public abstract class Aircraft
{
protected IAirTrafficControl atc;    // 航空交通管制中心
protected string callSign;           // 呼号
protected bool isAirborne;           // 是否在空中
// 构造函数
public Aircraft(string callSign, IAirTrafficControl atc)
{
this.callSign = callSign;
this.atc = atc;
this.isAirborne = false;
// 向管制中心注册
atc.RegisterAircraft(this);
}
// 获取呼号
public string GetCallSign()
{
return callSign;
}
// 接收消息
public void ReceiveMessage(string message)
{
Console.WriteLine($"{callSign} 收到消息: {message}");
}
// 发送消息到管制中心
public void SendMessage(string message)
{
Console.WriteLine($"{callSign} 发送消息: {message}");
atc.SendMessage(message, this);
}
// 请求起飞
public void RequestTakeoff()
{
if (!isAirborne)
{
Console.WriteLine($"{callSign} 请求起飞");
atc.RequestTakeoff(this);
}
else
{
Console.WriteLine($"{callSign} 已经在空中,无法起飞");
}
}
// 请求降落
public void RequestLanding()
{
if (isAirborne)
{
Console.WriteLine($"{callSign} 请求降落");
atc.RequestLanding(this);
}
else
{
Console.WriteLine($"{callSign} 已经在地面,无法降落");
}
}
// 起飞
public void Takeoff()
{
isAirborne = true;
Console.WriteLine($"{callSign} 起飞成功");
}
// 降落
public void Land()
{
isAirborne = false;
Console.WriteLine($"{callSign} 降落成功");
}
}
// 具体同事类:客机
public class CommercialAircraft : Aircraft
{
private int passengerCapacity; // 乘客容量
// 构造函数
public CommercialAircraft(string callSign, IAirTrafficControl atc, int passengerCapacity)
: base(callSign, atc)
{
this.passengerCapacity = passengerCapacity;
}
}
// 具体同事类:货机
public class CargoAircraft : Aircraft
{
private double cargoCapacity; // 货物容量(吨)
// 构造函数
public CargoAircraft(string callSign, IAirTrafficControl atc, double cargoCapacity)
: base(callSign, atc)
{
this.cargoCapacity = cargoCapacity;
}
}
// 具体中介者:航空交通管制中心
public class AirTrafficControlCenter : IAirTrafficControl
{
private Dictionary<string, Aircraft> aircrafts; // 注册的飞机
  private Queue<Aircraft> landingQueue;           // 降落队列
    private Queue<Aircraft> takeoffQueue;           // 起飞队列
      private bool runwayFree;                        // 跑道是否空闲
      // 构造函数
      public AirTrafficControlCenter()
      {
      aircrafts = new Dictionary<string, Aircraft>();
        landingQueue = new Queue<Aircraft>();
          takeoffQueue = new Queue<Aircraft>();
            runwayFree = true;
            }
            // 注册飞机
            public void RegisterAircraft(Aircraft aircraft)
            {
            string callSign = aircraft.GetCallSign();
            if (!aircrafts.ContainsKey(callSign))
            {
            aircrafts.Add(callSign, aircraft);
            Console.WriteLine($"飞机 {callSign} 已注册到管制中心");
            }
            }
            // 广播消息给所有飞机,除了发送者
            public void SendMessage(string message, Aircraft sender)
            {
            foreach (var aircraft in aircrafts.Values)
            {
            if (aircraft != sender)
            {
            aircraft.ReceiveMessage(message);
            }
            }
            }
            // 请求降落
            public void RequestLanding(Aircraft aircraft)
            {
            landingQueue.Enqueue(aircraft);
            Console.WriteLine($"飞机 {aircraft.GetCallSign()} 已加入降落队列,当前队列长度: {landingQueue.Count}");
            // 如果跑道空闲,处理下一个降落请求
            if (runwayFree)
            {
            ProcessNextOperation();
            }
            }
            // 请求起飞
            public void RequestTakeoff(Aircraft aircraft)
            {
            takeoffQueue.Enqueue(aircraft);
            Console.WriteLine($"飞机 {aircraft.GetCallSign()} 已加入起飞队列,当前队列长度: {takeoffQueue.Count}");
            // 如果跑道空闲,处理下一个起飞请求
            if (runwayFree)
            {
            ProcessNextOperation();
            }
            }
            // 处理下一个操作(降落或起飞)
            private void ProcessNextOperation()
            {
            // 降落优先级高于起飞
            if (landingQueue.Count > 0)
            {
            ProcessLanding();
            }
            else if (takeoffQueue.Count > 0)
            {
            ProcessTakeoff();
            }
            }
            // 处理降落
            private void ProcessLanding()
            {
            if (landingQueue.Count > 0)
            {
            runwayFree = false;
            Aircraft aircraft = landingQueue.Dequeue();
            Console.WriteLine($"管制中心授权 {aircraft.GetCallSign()} 降落");
            // 模拟降落过程
            aircraft.Land();
            // 完成后释放跑道
            runwayFree = true;
            // 处理下一个操作
            ProcessNextOperation();
            }
            }
            // 处理起飞
            private void ProcessTakeoff()
            {
            if (takeoffQueue.Count > 0)
            {
            runwayFree = false;
            Aircraft aircraft = takeoffQueue.Dequeue();
            Console.WriteLine($"管制中心授权 {aircraft.GetCallSign()} 起飞");
            // 模拟起飞过程
            aircraft.Takeoff();
            // 完成后释放跑道
            runwayFree = true;
            // 处理下一个操作
            ProcessNextOperation();
            }
            }
            }
            // 客户端代码
            public class Program
            {
            static void Main(string[] args)
            {
            // 创建航空交通管制中心(中介者)
            IAirTrafficControl atc = new AirTrafficControlCenter();
            // 创建各种飞机(同事)
            Aircraft flight1 = new CommercialAircraft("CA1234", atc, 200);
            Aircraft flight2 = new CommercialAircraft("MU5678", atc, 180);
            Aircraft flight3 = new CargoAircraft("CK8765", atc, 50.5);
            // 模拟飞机操作
            Console.WriteLine("\n模拟飞机操作:");
            // 飞机1请求起飞
            flight1.RequestTakeoff();
            // 飞机2请求起飞
            flight2.RequestTakeoff();
            // 飞机1向所有飞机发送消息
            flight1.SendMessage("天气晴朗,航行顺利");
            // 飞机1请求降落
            flight1.RequestLanding();
            // 飞机3请求起飞
            flight3.RequestTakeoff();
            // 飞机2请求降落
            flight2.RequestLanding();
            }
            }

6. 中介者模式的优缺点

6.1 优点

  1. 降低了系统的复杂度:将网状结构转变为星型结构,减少了类之间的直接依赖。

  2. 增强了系统的可维护性:当一个对象发生变化时,只需要通知中介者,而不用通知其他所有对象。

  3. 提高了系统的可复用性:由于同事类与中介者的松散耦合,同事类可以在不同系统中复用。

  4. 简化了对象间的协议:对象只需与中介者通信,而不需要了解其他对象的接口。

6.2 缺点

  1. 中介者可能过于复杂:随着系统的扩大,中介者可能会变得过于庞大和复杂,形成一个难以维护的"上帝类"。

  2. 系统性能可能下降:所有的交互都要经过中介者,可能会导致系统性能下降。

  3. 可能导致功能集中:过度使用中介者模式可能导致功能过度集中,违反分布式的设计原则。

7. 中介者模式的变体

7.1 事件聚合器(Event Aggregator)

事件聚合器是中介者模式的一种变体,它允许对象间通过事件机制进行通信,而不需要直接引用彼此。这在大型应用程序中特别有用,可以简化模块间的通信。

using System;
using System.Collections.Generic;
// 事件基类
public abstract class ApplicationEvent
{
// 事件类型
public abstract string GetEventType();
}
// 具体事件:用户登录事件
public class UserLoggedInEvent : ApplicationEvent
{
public string Username { get; private set; }
public UserLoggedInEvent(string username)
{
Username = username;
}
public override string GetEventType()
{
return "UserLoggedIn";
}
}
// 具体事件:消息接收事件
public class MessageReceivedEvent : ApplicationEvent
{
public string Sender { get; private set; }
public string Content { get; private set; }
public MessageReceivedEvent(string sender, string content)
{
Sender = sender;
Content = content;
}
public override string GetEventType()
{
return "MessageReceived";
}
}
// 事件处理器接口
public interface IEventHandler<T> where T : ApplicationEvent
  {
  void Handle(T eventData);
  }
  // 事件聚合器(中介者)
  public class EventAggregator
  {
  // 单例实例
  private static EventAggregator instance;
  // 事件处理器字典
  private Dictionary<string, List<object>> handlers = new Dictionary<string, List<object>>();
    // 私有构造函数
    private EventAggregator()
    {
    }
    // 获取单例实例
    public static EventAggregator Instance
    {
    get
    {
    if (instance == null)
    {
    instance = new EventAggregator();
    }
    return instance;
    }
    }
    // 订阅事件
    public void Subscribe<T>(IEventHandler<T> handler) where T : ApplicationEvent
      {
      string eventType = GetEventTypeName<T>();
        if (!handlers.ContainsKey(eventType))
        {
        handlers[eventType] = new List<object>();
          }
          if (!handlers[eventType].Contains(handler))
          {
          handlers[eventType].Add(handler);
          }
          }
          // 取消订阅事件
          public void Unsubscribe<T>(IEventHandler<T> handler) where T : ApplicationEvent
            {
            string eventType = GetEventTypeName<T>();
              if (handlers.ContainsKey(eventType))
              {
              handlers[eventType].Remove(handler);
              }
              }
              // 发布事件
              public void Publish<T>(T eventData) where T : ApplicationEvent
                {
                string eventType = eventData.GetEventType();
                if (handlers.ContainsKey(eventType))
                {
                foreach (var handler in handlers[eventType])
                {
                ((IEventHandler<T>)handler).Handle(eventData);
                  }
                  }
                  }
                  // 获取事件类型名称
                  private string GetEventTypeName<T>() where T : ApplicationEvent
                    {
                    // 创建类型的实例以获取事件类型名称
                    // 注意:这不是最优方法,但为了简化示例
                    T instance = Activator.CreateInstance<T>();
                      return instance.GetEventType();
                      }
                      }
                      // 登录模块:发布登录事件
                      public class LoginModule
                      {
                      private EventAggregator eventAggregator;
                      public LoginModule()
                      {
                      eventAggregator = EventAggregator.Instance;
                      }
                      public void Login(string username, string password)
                      {
                      // 在实际应用中,这里会有身份验证逻辑
                      if (password == "password") // 简化的验证逻辑
                      {
                      Console.WriteLine($"用户 {username} 登录成功");
                      // 发布登录成功事件
                      eventAggregator.Publish(new UserLoggedInEvent(username));
                      }
                      else
                      {
                      Console.WriteLine($"用户 {username} 登录失败:密码错误");
                      }
                      }
                      }
                      // 聊天模块:处理登录事件和发布消息事件
                      public class ChatModule : IEventHandler<UserLoggedInEvent>
                        {
                        private EventAggregator eventAggregator;
                        private List<string> onlineUsers = new List<string>();
                          public ChatModule()
                          {
                          eventAggregator = EventAggregator.Instance;
                          // 订阅登录事件
                          eventAggregator.Subscribe<UserLoggedInEvent>(this);
                            }
                            // 处理登录事件
                            public void Handle(UserLoggedInEvent eventData)
                            {
                            onlineUsers.Add(eventData.Username);
                            Console.WriteLine($"聊天模块:用户 {eventData.Username} 上线,当前在线用户数:{onlineUsers.Count}");
                            }
                            // 发送消息
                            public void SendMessage(string sender, string content)
                            {
                            if (onlineUsers.Contains(sender))
                            {
                            Console.WriteLine($"聊天模块:用户 {sender} 发送消息:{content}");
                            // 发布消息接收事件
                            eventAggregator.Publish(new MessageReceivedEvent(sender, content));
                            }
                            else
                            {
                            Console.WriteLine($"聊天模块:发送失败,用户 {sender} 不在线");
                            }
                            }
                            }
                            // 通知模块:处理消息事件
                            public class NotificationModule : IEventHandler<MessageReceivedEvent>
                              {
                              private EventAggregator eventAggregator;
                              public NotificationModule()
                              {
                              eventAggregator = EventAggregator.Instance;
                              // 订阅消息接收事件
                              eventAggregator.Subscribe<MessageReceivedEvent>(this);
                                }
                                // 处理消息接收事件
                                public void Handle(MessageReceivedEvent eventData)
                                {
                                Console.WriteLine($"通知模块:收到来自 {eventData.Sender} 的新消息通知");
                                }
                                }
                                // 客户端代码
                                public class Program
                                {
                                static void Main(string[] args)
                                {
                                // 创建各模块
                                LoginModule loginModule = new LoginModule();
                                ChatModule chatModule = new ChatModule();
                                NotificationModule notificationModule = new NotificationModule();
                                // 模拟用户登录
                                Console.WriteLine("模拟用户登录:");
                                loginModule.Login("alice", "password");
                                // 模拟发送消息
                                Console.WriteLine("\n模拟发送消息:");
                                chatModule.SendMessage("alice", "你好,这是一条测试消息!");
                                // 模拟未登录用户发送消息
                                Console.WriteLine("\n模拟未登录用户发送消息:");
                                chatModule.SendMessage("bob", "这条消息不会被发送,因为bob未登录");
                                // 模拟另一个用户登录
                                Console.WriteLine("\n模拟另一个用户登录:");
                                loginModule.Login("bob", "password");
                                // 再次发送消息
                                Console.WriteLine("\n再次发送消息:");
                                chatModule.SendMessage("bob", "现在我可以发送消息了!");
                                }
                                }

7.2 中介者与命令模式结合

中介者模式可以与命令模式结合,形成一种强大的模式组合,尤其适用于复杂的UI系统。命令对象封装操作,而中介者负责协调这些操作之间的关系。

8. 实现中介者模式的最佳实践

  1. 避免中介者过于复杂:当中介者变得过于复杂时,考虑将其分解为多个较小的中介者,每个负责特定的功能区域。

  2. 使用接口而非具体类:同事对象应该依赖于中介者接口,而不是具体的中介者类,这样可以提高系统的灵活性。

  3. 结合事件和委托:在C#中,利用事件和委托机制可以简化中介者模式的实现。

  4. 注意中介者的生命周期:确保中介者在其所有同事对象之前创建,并在它们之后销毁。

  5. 考虑单例模式:对于系统级别的中介者,可以考虑使用单例模式实现,确保整个系统只有一个中介者实例。

9. 总结

中介者模式是一种强大的行为型设计模式,它通过引入一个中介者对象来减少对象之间的直接依赖,从而降低系统的复杂度。它特别适用于对象间交互复杂的系统,如UI控件交互、聊天应用、航空交通管制等场景。

虽然中介者模式可以有效地减少类之间的耦合,但也需要注意避免中介者本身变得过于复杂。在实践中,可以将中介者模式与其他设计模式(如命令模式、观察者模式等)结合使用,以构建更加灵活和可维护的系统。

理解中介者模式与观察者模式的区别也很重要,这可以帮助我们在适当的场景选择合适的模式。总的来说,当系统中的对象需要复杂的相互交互时,中介者模式是一个值得考虑的解决方案。

参考资料和学习链接

  1. 设计模式:可复用面向对象软件的基础
  2. Head First 设计模式
  3. Refactoring.Guru - 中介者模式
  4. Dofactory - Mediator Pattern
  5. Event Aggregator Pattern

在这里插入图片描述

posted @ 2025-12-04 22:28  gccbuaa  阅读(9)  评论(0)    收藏  举报