动态

详情 返回 返回

掌握設計模式--中介者模式 - 动态 详情

中介者模式(Mediator Pattern)

中介者模式(Mediator Pattern)是一種行為型設計模式,它通過引入一箇中介者對象,來減少多個對象之間的直接依賴,使對象之間的通信變得鬆耦合。對象不直接相互引用,而是通過中介者與其他對象交互。這有助於提高系統的可維護性和擴展性。

核心思想: 將對象間複雜的依賴關係抽象到中介者中,從而使對象之間的依賴關係變得簡單。

主要組成部分

  • 中介者接口(Mediator): 定義了同事對象(Colleague)之間通信的接口。
  • 具體中介者(ConcreteMediator): 實現中介者接口,協調各同事對象的通信邏輯。
  • 同事類(Colleague): 持有中介者的引用,所有與其他同事的交互都通過中介者進行。

案例實現

以一個聊天系統為例,其中服務端作為中介者協調用户之間的通信。該案例不完全是中介者設計模式,但中介者模式的思想仍然保留服務器端負責協調各客户端之間的通信。

案例交互關係

image

服務端作為中介者

服務器端管理用户信息及接收來自客户端的消息並將其廣播給其他客户端

public class ChatServer {
    private static final int PORT = 12345;
    private Set<ClientHandler> 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());
    }

}

處理客户端發來的消息

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();
        }
    }
}

客户端作為同事類

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. 發送消息:在任意客户端中輸入消息,服務器會將消息廣播給其他所有已連接的客户端。

示例輸出

服務器端:

服務器啓動,等待客户端連接...
新客户端連接:127.0.0.1
新客户端連接:127.0.0.1
收到消息:hi 1
收到消息:hi 2

客户端 1:

已連接到服務器,開始聊天...
hi 1
收到消息:hi 2

客户端 2:

已連接到服務器,開始聊天...
收到消息:hi 1
hi 2

優缺點和使用場景

優點

  1. 降低對象耦合性: 對象不再直接依賴,而是通過中介者交互。
  2. 集中控制複雜度: 中介者封裝了對象間的交互邏輯,簡化了對象管理。
  3. 易於擴展: 新增同事類時,只需在中介者中添加相應的處理邏輯,無需修改現有同事類。

缺點

  1. 中介者複雜性提升: 隨着同事類和交互邏輯的增加,中介者可能變得臃腫難以維護。
  2. 潛在性能問題: 由於所有交互通過中介者處理,可能導致性能瓶頸。

使用場景

  • 多個對象之間的交互複雜且邏輯分散;
  • 系統中需要一個集中管理的通信控制器;
  • 需要解耦對象間的依賴。

中介者模式的應用

Spring MVC的核心組件DispatcherServlet作為中介者,協調請求的處理過程。它調度不同的組件(HandlerMappingHandlerAdapterViewResolver等)完成請求的分發和響應生成。DispatcherServlet負責管理整個請求的生命週期,避免了組件之間的直接耦合。

總結

中介者模式適合用於多對象複雜交互的場景,通過引入中介者降低耦合度,集中管理交互邏輯。然而,要避免中介者變得過於複雜,需要合理設計中介者的職責邊界。

注意事項

當中介者的邏輯過於複雜時,可以將其拆分為多箇中介者或使用其他設計模式輔助管理複雜性。

在某些場景下,中介者模式可能被事件總線、觀察者模式替代,根據實際需求選擇適合的模式。

image

需要查看往期設計模式文章的,可以在個人主頁中或者文章開頭的集合中查看,可關注我,持續更新中。。。


超實用的SpringAOP實戰之日誌記錄

2023年下半年軟考考試重磅消息

通過軟考後卻領取不到實體證書?

計算機算法設計與分析(第5版)

Java全棧學習路線、學習資源和麪試題一條龍

軟考證書=職稱證書?

軟考中級--軟件設計師毫無保留的備考分享

user avatar FreakEmbedded 头像
点赞 1 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.