C++ 設計模式 - 中介者模式 Mediator Pattern

有時候我們在開發大型系統時,會發現各個物件之間的溝通漸漸變得複雜無比,像是織了一張錯綜複雜的蜘蛛網。每個物件彼此依賴,要新增或修改功能時牽一髮而動全身。這時候中介者模式 Mediator Pattern 就像是一個「協調者」,能讓物件之間的溝通變得有條不紊,不用每個物件都互相認識。今天我們來聊聊這個神奇的模式!

什麼是中介者模式?

中介者模式是一種行為型設計模式,用來定義一個物件,負責協調其他多個物件之間的互動。這個模式的核心概念是:物件之間不直接溝通,而是透過一個「中介者」來傳遞訊息或協調行為。這樣做的好處是,我們可以減少物件之間的耦合度,使系統更易於維護與擴展。

打個比方,想像你在公司裡面工作,當你需要和不同部門溝通時,不需要直接找每個部門的人,而是透過人力資源部門(HR)。HR 就是這裡的「中介者」,它負責協調你與各部門之間的溝通,讓事情變得更簡單明瞭。

中介者模式在聊天室應用中的實例

最經典的中介者模式應用場景之一就是「聊天室」。在一個聊天室中,每個使用者都可以發訊息給其他使用者。如果沒有中介者模式,所有使用者都需要相互認識才能互相溝通,這會讓系統變得非常混亂且難以擴展。而有了中介者後,每個使用者只需要和中介者溝通,中介者再把訊息傳遞給其他相關的使用者。

首先我們先定義中介者介面,中介者需要有一個統一的介面,定義訊息如何在物件間傳遞,

1
2
3
4
5
6
7
8
class ChatUser; // 前向宣告

// 中介者介面
class ChatRoom {
public:
virtual void sendMessage(const ChatUser* sender, const std::string& message) = 0;
virtual ~ChatRoom() = default;
};

這個具體的中介者負責管理聊天室中的使用者,並將訊息傳遞給正確的接收者,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 具體中介者
class ConcreteChatRoom : public ChatRoom {
private:
std::vector<ChatUser*> chatUsers;

public:
void addUser(ChatUser* user) {
chatUsers.push_back(user);
}

void sendMessage(const ChatUser* sender, const std::string& message) override {
for (ChatUser* user : chatUsers) {
if (user != sender) {
user->receive(sender->getName() + ": " + message);
}
}
}
};

聊天室的使用者實作一個可以和中介者溝通的介面,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 參與者
class ChatUser {
private:
std::string name;
ChatRoom* chatRoom;

public:
ChatUser(const std::string& name, ChatRoom* room) : name(name), chatRoom(room) {}

void send(const std::string& message) const {
std::cout << name << " 發送消息: " << message << std::endl;
chatRoom->sendMessage(this, message);
}

void receive(const std::string& message) {
std::cout << name << " 收到消息: " << message << std::endl;
}

std::string getName() const {
return name;
}
};

在客戶端,使用者透過中介者來發送和接收訊息,而不需要知道其他使用者的存在,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 客戶端使用
int main() {
ConcreteChatRoom room;

ChatUser john("John", &room);
ChatUser alice("Alice", &room);

room.addUser(&john);
room.addUser(&alice);

john.send("Hello, Alice!");
alice.send("Hi, John!");

return 0;
}

執行上述程式碼,我們會得到以下輸出:

1
2
3
4
John 發送消息: Hello, Alice!
Alice 收到消息: John: Hello, Alice!
Alice 發送消息: Hi, John!
John 收到消息: Alice: Hi, John!

中介者模式的優缺點

中介者模式最大的優勢是「解耦」,它避免了各個物件直接互相依賴,這使得系統結構更加清晰,新增或移除物件時,不需要修改其他物件的程式碼。同時,這也讓我們可以更靈活地修改中介者的行為,達到自訂溝通規則的目的。

中介者模式也有其潛在的缺點。隨著系統的擴展,中介者本身可能會變得非常複雜,尤其當有很多物件要透過中介者溝通時,這個中介者可能會變成一個大型的、難以維護的類別,反而會增加系統的負擔。

總結

中介者模式特別適合應用於多個物件需要互相溝通的情況下,比如聊天室、事件處理系統等。透過中介者可以有效地減少物件之間的耦合,讓系統更加靈活。當然和其他設計模式一樣,我們也要根據具體的需求謹慎使用,避免讓中介者本身變得過於複雜。