[Design Pattern] 중재자 패턴

Mediator Pattern

중재자 패턴은 한 집합에 속해있는 객체의 상호작용을 캡슐화하는 객체를 정의하는 패턴이다. 객체들이 직접 서로를 참조하지 않도록하여 객체 사이에 결합도를 낮추며 개발자가 객체의 상호작용을 독립적으로 다양화시킬 수 있게 한다.

활용성

  1. 여러 객체가 잘 정의된 형태지만 복잡한 상호작용을 가질 때
  2. 한 객체가 다른 객체를 너무 많이 참조하고 너무 많은 의사소통을 해서 재사용하기 힘들 때
  3. 여러 클래스에 분산된 행동들이 상속 없이 상황에 맞게 수정되어야 할 때

중재자 패턴 사용에 따른 결과

서브클래싱 제한

중재자는 다른 객체 사이에 분산된 객체의 행동들을 하나의 객체로 국한한다. 이 행동을 변경하고자 한다면 Mediator 클래스를 상속하는 서브 클래스만 만들면 되며 Colleague 클래스는 재사용 가능하다.

Colleague 객체 사이의 종속성 저하

중재자는 행동에 참여하는 객체간 결합도를 낮춘다.

객체 프로토콜 단순화

중재자는 다 : 다의 관계를 일 : 다의 관계로 축소시킨다.

객체간 협력 방법 추상화

객체 사이에 독립적인 중재자를 두고 이것을 통해 캡슐화 함으로써 사용자는 객체의 행동과 상관없이 객체간 연결 방법에만 집중할 수 있다.

통제 집중화

중재자 패턴은 모든 상호작용이 중재자 안에서만 이루어지기 때문에 어느 객체보다도 제일 복잡해질 가능성이 크다.

중재자

구조

중재자의 구조는 다음과 같다.

Mediator Pattern Diagram

C++ 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void MediatorPattern::MediatorPattern()
{
IChatClient* client1 = new ChatClient("Client1");
IChatClient* client2 = new ChatClient("Client2");
IChatClient* client3 = new ChatClient("Client3");
IChatClient* client4 = new ChatClient("Client4");
IChatClient* client5 = new ChatClient("Client5");
IChatMediator* mediator = new ChatMediator(4, client1, client2, client3, client4);

client1->setMediator(mediator);
client2->setMediator(mediator);
client3->setMediator(mediator);
client4->setMediator(mediator);

client1->send("Hello");
client2->send("Hi Client1");
client3->send("Bye");

client3->quit();

mediator->addClient(client5);
client5->setMediator(mediator);

client5->send("I`m noob");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class IChatMediator;
class IChatClient
{
public:
virtual ~IChatClient() {}
virtual void setMediator(IChatMediator* mediator) = 0;
virtual void display(std::string message) = 0;
virtual void send(std::string message) = 0;
virtual void quit() = 0;
};

class ChatClient : public IChatClient
{
IChatMediator* mediator;
std::string name;
public:
ChatClient(IChatMediator* mediator, std::string name) : mediator(mediator), name(name) {}
ChatClient(std::string name) : name(name) {}

void setMediator(IChatMediator* mediator) override
{
this->mediator = mediator;
}

void display(std::string message) override
{
std::cout<<name<<" : "<<message<<std::endl;
}

void send(std::string message) override
{
mediator->mediate(this, "From " + this->name + " : " + message);
}

void quit() override
{
mediator->removeClient(this);
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class IChatClient;
class IChatMediator
{
public:
virtual ~IChatMediator() {}
virtual void addClient(IChatClient* chatClient) = 0;
virtual void removeClient(IChatClient* chatClient) = 0;
virtual void mediate(IChatClient* chatClient, std::string message) = 0;
};

class ChatMediator : public IChatMediator
{
std::vector<IChatClient*> clients;

public:
ChatMediator() {}

ChatMediator(int args, ...)
{
va_list ap;

va_start(ap, args);
for(int i = 0; i < args; i++)
clients.push_back(va_arg(ap,IChatClient*));
va_end(ap);
}

void addClient(IChatClient* chatClient) override
{
clients.push_back(chatClient);
}

void removeClient(IChatClient* chatClient) override
{
for(auto it = clients.begin(); it != clients.end(); ++it)
if(*it == chatClient)
clients.erase(it);
}

void mediate(IChatClient* chatClient, std::string message) override
{
for(auto client : clients)
if(client != chatClient)
client->display(message);
}
};

java 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Client {
public static void main(String[] args) {
ChatClient client1 = new ChatClientImpl("Client1");
ChatClient client2 = new ChatClientImpl("Client2");
ChatClient client3 = new ChatClientImpl("Client3");
ChatClient client4 = new ChatClientImpl("Client4");
ChatClient client5 = new ChatClientImpl("Client5");
Mediator mediator = new MediatorImpl(client1, client2, client3, client4);

client1.setMediator(mediator);
client2.setMediator(mediator);
client3.setMediator(mediator);
client4.setMediator(mediator);

client1.send("Hello");
client2.send("Hi Client1");
client3.send("Bye");

client3.quit();

mediator.addClient(client5);
client5.setMediator(mediator);

client5.send("I`m noob");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public interface ChatClient {
void setMediator(Mediator mediator);
void display(String message);
void send(String message);
void quit();
}

public class ChatClientImpl implements ChatClient{
private Mediator mediator;
private String name;

public ChatClientImpl(String name) {
this.name = name;
}

@Override
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}

@Override
public void send(String message) {
mediator.mediate(this, "From " + name + " : " + message);
}

@Override
public void display(String message) {
System.out.println(name + " : " + message);
}

@Override
public void quit() {
mediator.removeClient(this);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public interface Mediator {
void addClient(ChatClient client);
void removeClient(ChatClient client);
void mediate(ChatClient client, String message);
}

public class MediatorImpl implements Mediator{
private List<ChatClient> clients;

public MediatorImpl() {
this.clients = new ArrayList<>();
}

public MediatorImpl(ChatClient client) {
this();
clients.add(client);
}

public MediatorImpl(ChatClient client, ChatClient... varClients) {
this(client);
for(ChatClient chatClient : varClients)
clients.add(chatClient);
}

@Override
public void addClient(ChatClient client) {
clients.add(client);
}

@Override
public void removeClient(ChatClient client) {
clients.remove(client);
}

@Override
public void mediate(ChatClient client, String message) {
for(ChatClient chatClient : clients)
if(!chatClient.equals(client))
chatClient.display(message);
}
}
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/25/Design%20Pattern/MediatorPattern/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.