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

流光溢彩 / 03-31 / 19点赞 / 0评论 / 755阅读
## 中介者模式(Mediator Pattern) **中介者模式**(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象,来减少多个对象之间的直接依赖,使对象之间的通信变得松耦合。对象不直接相互引用,而是通过中介者与其他对象交互。这有助于提高系统的可维护性和扩展性。 **核心思想:** 将对象间复杂的`依赖关系`**抽象到**`中介者`中,从而使对象之间的依赖关系变得简单。 ### 主要组成部分 - **中介者接口(Mediator):** 定义了同事对象(Colleague)之间通信的接口。 - **具体中介者(ConcreteMediator):** 实现中介者接口,协调各同事对象的通信逻辑。 - **同事类(Colleague):** 持有中介者的引用,所有与其他同事的交互都通过中介者进行。 ## 案例实现 以一个聊天系统为例,其中服务端作为中介者协调用户之间的通信。该案例不完全是中介者设计模式,但**中介者模式的思想仍然保留**服务器端负责协调各客户端之间的通信。 ### 案例交互关系 ![image](https://cdn.res.knowhub.vip/c/2504/01/beb9bb36.png?G1UAAMTydJz4%2b0PRbdTh20SR0AxIZBFUSliv95y1b5HvN4LRP6P1afvDX1qfJkpUaBaCCQFO89JEJNWiLlJLrch%2bDQM%3d) ### 服务端作为中介者 服务器端管理用户信息及接收来自客户端的消息并将其广播给其他客户端 ```java public class ChatServer { private static final int PORT = 12345; private Set clients = new HashSet<>(); public static void main(String[] args) { new ChatServer().startServer(); } public void startServer() { try (ServerSocket serverSocket = new ServerSocket(PORT)) { System.out.println("服务器启动,等待客户端连接..."); while (true) { Socket socket = serverSocket.accept(); System.out.println("新客户端连接:" + socket.getInetAddress().getHostAddress()); // 处理用户发来的信息 ClientHandler clientHandler = new ClientHandler(socket, this); clients.add(clientHandler); new Thread(clientHandler).start(); } } catch (IOException e) { e.printStackTrace(); } } /** * 中介者分发消息 * @param message 信息 * @param sender 发送者 */ public synchronized void broadcast(String message, ClientHandler sender) { for (ClientHandler client : clients) { if (client != sender) { client.sendMessage(message); } } } public synchronized void removeClient(ClientHandler clientHandler) { clients.remove(clientHandler); System.out.println("客户端断开连接:" + clientHandler.getSocket().getInetAddress().getHostAddress()); } } ``` ### 处理客户端发来的消息 ```java public class ClientHandler implements Runnable { private Socket socket; private ChatServer server; private PrintWriter out; public ClientHandler(Socket socket, ChatServer server) { this.socket = socket; this.server = server; } public Socket getSocket() { return socket; } @Override public void run() { try ( InputStream input = socket.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(input)) ) { out = new PrintWriter(socket.getOutputStream(), true); String message; while ((message = reader.readLine()) != null) { System.out.println("收到消息:" + message); server.broadcast(message, this); } } catch (IOException e) { System.out.println("客户端连接异常:" + e.getMessage()); } finally { server.removeClient(this); closeSocket(); } } public void sendMessage(String message) { if (out != null) { out.println(message); } } private void closeSocket() { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` ### 客户端作为同事类 ```java public class ChatClient { private static final String SERVER_HOST = "localhost"; private static final int SERVER_PORT = 12345; public static void main(String[] args) { try ( Socket socket = new Socket(SERVER_HOST, SERVER_PORT); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())) ) { System.out.println("已连接到服务器,开始聊天..."); // 启动线程处理接收消息 new Thread(() -> { try { String message; while ((message = in.readLine()) != null) { System.out.println("收到消息:" + message); } } catch (IOException e) { System.out.println("服务器断开连接:" + e.getMessage()); } }).start(); // 主线程负责发送消息 Scanner scanner = new Scanner(System.in); while (true) { String message = scanner.nextLine(); out.println(message); } } catch (IOException e) { e.printStackTrace(); } } } ``` ### 测试步骤 1. **运行服务器端**:启动 `ChatServer`,它会监听指定端口(12345)。 2. **运行多个客户端**:启动多个 `ChatClient` 实例,每个客户端会连接到服务器。 3. **发送消息**:在任意客户端中输入消息,服务器会将消息广播给其他所有已连接的客户端。 ### 示例输出 **服务器端:** ```csharp 服务器启动,等待客户端连接... 新客户端连接:127.0.0.1 新客户端连接:127.0.0.1 收到消息:hi 1 收到消息:hi 2 ``` **客户端 1:** ```csharp 已连接到服务器,开始聊天... hi 1 收到消息:hi 2 ``` **客户端 2:** ```csharp 已连接到服务器,开始聊天... 收到消息:hi 1 hi 2 ``` ## 优缺点和使用场景 ### 优点 1. **降低对象耦合性:** 对象不再直接依赖,而是通过中介者交互。 2. **集中控制复杂度:** 中介者封装了对象间的交互逻辑,简化了对象管理。 3. **易于扩展:** 新增同事类时,只需在中介者中添加相应的处理逻辑,无需修改现有同事类。 ### 缺点 1. **中介者复杂性提升:** 随着同事类和交互逻辑的增加,中介者可能变得臃肿难以维护。 2. **潜在性能问题:** 由于所有交互通过中介者处理,可能导致性能瓶颈。 ### 使用场景 - 多个对象之间的交互复杂且逻辑分散; - 系统中需要一个集中管理的通信控制器; - 需要解耦对象间的依赖。 ## 中介者模式的应用 Spring MVC的核心组件`DispatcherServlet`作为中介者,协调请求的处理过程。它调度不同的组件(`HandlerMapping`、`HandlerAdapter`、`ViewResolver`等)完成请求的分发和响应生成。`DispatcherServlet`负责管理整个请求的生命周期,避免了组件之间的直接耦合。 ## 总结 中介者模式适合用于多对象复杂交互的场景,通过引入中介者降低耦合度,集中管理交互逻辑。然而,要避免中介者变得过于复杂,需要合理设计中介者的职责边界。 **注意事项** 当中介者的逻辑过于复杂时,可以将其拆分为多个中介者或使用其他设计模式辅助管理复杂性。 在某些场景下,中介者模式可能被事件总线、观察者模式替代,根据实际需求选择适合的模式。