C++ - 중재자, 미디에이터 패턴 (Mediator Pattern)
Architecture & Design Pattern 전체 링크
중재자, 미디에이터 패턴 (Mediator Pattern) - 행동 패턴
- 객체 간의 상호작용을 캡슐화하여 복잡한 통신과 제어를 한 곳으로 집중시키는 패턴
- 객체 간의 직접적인 통신을 방지하여 결합도를 낮춘다.
구현
- Mediator : 객체들 간의 상호작용을 관리하고 조정하는 주체, 중재자는 요청을 받아들이고 적절한 객체에 전달한다.
- Colleague : 중재자를 통해 상호작용하는 객체, 다른 Colleague 객체와 직접 통신하지 않는다.
장점
- SRP(단일 책임 원칙), 다양한 Colleague간의 상호작용을 한 곳으로 추출한다.
- OCP(개방-폐쇄 원칙), 기존의 Colleague를 변경하지 않고 새로운 Collegue를 추가할 수 있다.
- 프로그램의 Colleague간의 결합도를 줄이고 개별 Colleague를 쉽게 재사용할 수 있다.
단점
- Mediator를 통해 간접적으로 통신해야 하므로 추가 오버헤드가 발생한다.
- 프로젝트가 커질수록 Mediator가 복잡해진다.
채팅
User 1 ~ 4가 채팅을 하려고 한다.
User1이 메시지를 send하면, User1을 제외한 모든 User는 메시지를 receive 해야 한다.
즉, 아래와 같이 서로 다른 객체들이 직접 상호작용을 해야 한다.
미디에이터 패턴 적용
채팅을 하기 위해서 유저가 서로 상호작용을 하는 것보다, 채팅방이 중재를 해주는 것이 좋다.
여기서 채팅방이 Mediator가 된다.
User(= Collegue)는 채팅방에 메시지를 send 하고, 채팅방은 적절한 User가 receive 할 수 있도록 중재한다.
미디에이터 인터페이스는 메시지와 참가자(User)를 파라미터로 받는 send를 구현하도록 한다.
class ChatRoomMediator
{
public:
virtual void send(const string& msg, Participant* participant) = 0;
};
실제 중재자인 ChatRoom은 User를 추가하는 메서드를 제공한다.
그리고 모든 User를 순회하면서 누가 메시지를 받을지 구현한다.
class ChatRoom : public ChatRoomMediator
{
public:
void addParticipant(Participant* participant) { participants.push_back(participant); }
void send(const string& msg, Participant* sender) override
{
for (Participant* participant : participants)
{
if (participant != sender)
participant->receive(msg);
}
}
private:
vector<Participant*> participants;
};
참가자 인터페이스는 다음과 같다.
User도 어떤 채팅방에 참가해야 하는지 알기 위해 생성자에서 채팅방(= Mediator)을 전달받아야 한다.
// Colleague
class Participant
{
public:
Participant(const string& n, ChatRoomMediator* crm) : name(n), mediator(crm) {}
void send(const string& msg) { mediator->send(msg + " from [" + name + "]", this); }
virtual void receive(const string& msg) = 0;
protected:
string name;
ChatRoomMediator* mediator;
};
Concrete Participant인 User는 receive를 구현한다.
여기서는 어떤 User가 어떤 메시지를 전달받는지 출력하였다.
class User : public Participant
{
public:
User(const string& name, ChatRoomMediator* mediator) : Participant(name, mediator) {}
void receive(const string& msg) override { cout << name << " is Received : " << msg << endl; }
};
이제 각 User 별로 채팅방에 메시지를 보내보자.
cout << "User1 send message." << endl;
user1->sendMessage("Hello, everyone!"); cout << endl;
cout << "User2 send message." << endl;
user2->sendMessage("Hi, User1!"); cout << endl;
cout << "User3 send message." << endl;
user3->sendMessage("Hey there!"); cout << endl;
cout << "User4 send message." << endl;
user4->sendMessage("My Name is User4"); cout << endl;
User1이 Message를 보낼 경우, 채팅방을 참여한 유저 중, User1을 제외한 모든 유저가 메시지를 받는다.
전체 코드는 다음과 같다.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Participant;
// Interface
class ChatRoomMediator
{
public:
virtual void send(const string& msg, Participant* participant) = 0;
};
// Colleague
class Participant
{
public:
Participant(const string& name, ChatRoomMediator* mediator) : name(name), mediator(mediator) {}
void send(const string& msg) { mediator->send(msg + " from [" + name + "]", this); }
virtual void receive(const string& msg) = 0;
protected:
string name;
ChatRoomMediator* mediator;
};
class ChatRoom : public ChatRoomMediator
{
public:
void addParticipant(Participant* participant) { participants.push_back(participant); }
void send(const string& msg, Participant* sender) override
{
for (Participant* participant : participants)
{
if (participant != sender)
participant->receive(msg);
}
}
private:
vector<Participant*> participants;
};
class User : public Participant
{
public:
User(const string& name, ChatRoomMediator* mediator) : Participant(name, mediator) {}
void receive(const string& msg) override { cout << name << " is Received : " << msg << endl; }
};
int main()
{
ChatRoom* chatRoom = new ChatRoom();
User* user1 = new User("User1", chatRoom);
User* user2 = new User("User2", chatRoom);
User* user3 = new User("User3", chatRoom);
User* user4 = new User("User4", chatRoom);
chatRoom->addParticipant(user1);
chatRoom->addParticipant(user2);
chatRoom->addParticipant(user3);
chatRoom->addParticipant(user4);
cout << "User1 send message." << endl;
user1->send("Hello, everyone!"); cout << endl;
cout << "User2 send message." << endl;
user2->send("Hi, User1!"); cout << endl;
cout << "User3 send message." << endl;
user3->send("Hey there!"); cout << endl;
cout << "User4 send message." << endl;
user4->send("My Name is User4"); cout << endl;
return 0;
}