找回密码
 立即注册
首页 业界区 业界 掌握设计模式--中介者模式

掌握设计模式--中介者模式

秦晓曼 2025-6-3 10:49:03
中介者模式(Mediator Pattern)

中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象,来减少多个对象之间的直接依赖,使对象之间的通信变得松耦合。对象不直接相互引用,而是通过中介者与其他对象交互。这有助于提高系统的可维护性和扩展性。
核心思想: 将对象间复杂的依赖关系抽象到中介者中,从而使对象之间的依赖关系变得简单。
主要组成部分


  • 中介者接口(Mediator): 定义了同事对象(Colleague)之间通信的接口。
  • 具体中介者(ConcreteMediator): 实现中介者接口,协调各同事对象的通信逻辑。
  • 同事类(Colleague): 持有中介者的引用,所有与其他同事的交互都通过中介者进行。
案例实现

以一个聊天系统为例,其中服务端作为中介者协调用户之间的通信。该案例不完全是中介者设计模式,但中介者模式的思想仍然保留服务器端负责协调各客户端之间的通信。
案例交互关系

1.png

服务端作为中介者

服务器端管理用户信息及接收来自客户端的消息并将其广播给其他客户端
  1. public class ChatServer {
  2.     private static final int PORT = 12345;
  3.     private Set<ClientHandler> clients = new HashSet<>();
  4.     public static void main(String[] args) {
  5.         new ChatServer().startServer();
  6.     }
  7.     public void startServer() {
  8.         try (ServerSocket serverSocket = new ServerSocket(PORT)) {
  9.             System.out.println("服务器启动,等待客户端连接...");
  10.             while (true) {
  11.                 Socket socket = serverSocket.accept();
  12.                 System.out.println("新客户端连接:" + socket.getInetAddress().getHostAddress());
  13.                 // 处理用户发来的信息
  14.                 ClientHandler clientHandler = new ClientHandler(socket, this);
  15.                 clients.add(clientHandler);
  16.                 new Thread(clientHandler).start();
  17.             }
  18.         } catch (IOException e) {
  19.             e.printStackTrace();
  20.         }
  21.     }
  22.     /**
  23.      * 中介者分发消息
  24.      * @param message 信息
  25.      * @param sender 发送者
  26.      */
  27.     public synchronized void broadcast(String message, ClientHandler sender) {
  28.         for (ClientHandler client : clients) {
  29.             if (client != sender) {
  30.                 client.sendMessage(message);
  31.             }
  32.         }
  33.     }
  34.     public synchronized void removeClient(ClientHandler clientHandler) {
  35.         clients.remove(clientHandler);
  36.         System.out.println("客户端断开连接:" + clientHandler.getSocket().getInetAddress().getHostAddress());
  37.     }
  38. }
复制代码
处理客户端发来的消息
  1. public class ClientHandler implements Runnable {
  2.     private Socket socket;
  3.     private ChatServer server;
  4.     private PrintWriter out;
  5.     public ClientHandler(Socket socket, ChatServer server) {
  6.         this.socket = socket;
  7.         this.server = server;
  8.     }
  9.     public Socket getSocket() {
  10.         return socket;
  11.     }
  12.     @Override
  13.     public void run() {
  14.         try (
  15.                 InputStream input = socket.getInputStream();
  16.                 BufferedReader reader = new BufferedReader(new InputStreamReader(input))
  17.         ) {
  18.             out = new PrintWriter(socket.getOutputStream(), true);
  19.             String message;
  20.             while ((message = reader.readLine()) != null) {
  21.                 System.out.println("收到消息:" + message);
  22.                 server.broadcast(message, this);
  23.             }
  24.         } catch (IOException e) {
  25.             System.out.println("客户端连接异常:" + e.getMessage());
  26.         } finally {
  27.             server.removeClient(this);
  28.             closeSocket();
  29.         }
  30.     }
  31.     public void sendMessage(String message) {
  32.         if (out != null) {
  33.             out.println(message);
  34.         }
  35.     }
  36.     private void closeSocket() {
  37.         try {
  38.             socket.close();
  39.         } catch (IOException e) {
  40.             e.printStackTrace();
  41.         }
  42.     }
  43. }
复制代码
客户端作为同事类
  1. public class ChatClient {
  2.     private static final String SERVER_HOST = "localhost";
  3.     private static final int SERVER_PORT = 12345;
  4.     public static void main(String[] args) {
  5.         try (
  6.                 Socket socket = new Socket(SERVER_HOST, SERVER_PORT);
  7.                 PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
  8.                 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))
  9.         ) {
  10.             System.out.println("已连接到服务器,开始聊天...");
  11.             // 启动线程处理接收消息
  12.             new Thread(() -> {
  13.                 try {
  14.                     String message;
  15.                     while ((message = in.readLine()) != null) {
  16.                         System.out.println("收到消息:" + message);
  17.                     }
  18.                 } catch (IOException e) {
  19.                     System.out.println("服务器断开连接:" + e.getMessage());
  20.                 }
  21.             }).start();
  22.             // 主线程负责发送消息
  23.             Scanner scanner = new Scanner(System.in);
  24.             while (true) {
  25.                 String message = scanner.nextLine();
  26.                 out.println(message);
  27.             }
  28.         } catch (IOException e) {
  29.             e.printStackTrace();
  30.         }
  31.     }
  32. }
复制代码
测试步骤


  • 运行服务器端:启动 ChatServer,它会监听指定端口(12345)。
  • 运行多个客户端:启动多个 ChatClient 实例,每个客户端会连接到服务器。
  • 发送消息:在任意客户端中输入消息,服务器会将消息广播给其他所有已连接的客户端。
示例输出

服务器端:
  1. 服务器启动,等待客户端连接...
  2. 新客户端连接:127.0.0.1
  3. 新客户端连接:127.0.0.1
  4. 收到消息:hi 1
  5. 收到消息:hi 2
复制代码
客户端 1:
  1. 已连接到服务器,开始聊天...
  2. hi 1
  3. 收到消息:hi 2
复制代码
客户端 2:
  1. 已连接到服务器,开始聊天...
  2. 收到消息:hi 1
  3. hi 2
复制代码
优缺点和使用场景

优点


  • 降低对象耦合性: 对象不再直接依赖,而是通过中介者交互。
  • 集中控制复杂度: 中介者封装了对象间的交互逻辑,简化了对象管理。
  • 易于扩展: 新增同事类时,只需在中介者中添加相应的处理逻辑,无需修改现有同事类。
缺点


  • 中介者复杂性提升: 随着同事类和交互逻辑的增加,中介者可能变得臃肿难以维护。
  • 潜在性能问题: 由于所有交互通过中介者处理,可能导致性能瓶颈。
使用场景


  • 多个对象之间的交互复杂且逻辑分散;
  • 系统中需要一个集中管理的通信控制器;
  • 需要解耦对象间的依赖。
中介者模式的应用

Spring MVC的核心组件DispatcherServlet作为中介者,协调请求的处理过程。它调度不同的组件(HandlerMapping、HandlerAdapter、ViewResolver等)完成请求的分发和响应生成。DispatcherServlet负责管理整个请求的生命周期,避免了组件之间的直接耦合。
总结

中介者模式适合用于多对象复杂交互的场景,通过引入中介者降低耦合度,集中管理交互逻辑。然而,要避免中介者变得过于复杂,需要合理设计中介者的职责边界。
注意事项
当中介者的逻辑过于复杂时,可以将其拆分为多个中介者或使用其他设计模式辅助管理复杂性。
在某些场景下,中介者模式可能被事件总线、观察者模式替代,根据实际需求选择适合的模式。
2.gif

需要查看往期设计模式文章的,可以在个人主页中或者文章开头的集合中查看,可关注我,持续更新中。。。
超实用的SpringAOP实战之日志记录
2023年下半年软考考试重磅消息
通过软考后却领取不到实体证书?
计算机算法设计与分析(第5版)
Java全栈学习路线、学习资源和面试题一条龙
软考证书=职称证书?
软考中级--软件设计师毫无保留的备考分享

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册