Thinking Different







Mediator Pattern - 중재자 패턴


  • 모든 클래스간의 복잡한 로직(상호작용)을 캡슐화하여 하나의 클래스에 위임하여 처리하는 패턴
  • M:N의 관계에서 M:1의 관계로 복잡도를 떨어뜨려 유지 보수 및 재사용의 확장성에 유리하다
  • 하나의 클래스가 떠맡아 처리해야 하므로 God(신) 클래스가 될 수 있으므로 주의해야한다
  • 비슷한 패턴으로 파사드 패턴 (Facade Pattern)과 옵저버 패턴 (Observer Pattern)이 있다.


샘플 코드)

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <list>
#include <typeinfo>
 
#if _UNICODE
typedef wstring tstring;
#else
typedef string tstring;
#endif
 
 
//------------------------------------------------------------------
// Mediator 인터페이스
class Colleague;    // 전방 선언
class Mediator
{
public:
    virtual void AddColleague(Colleague* colleague) = 0;
    virtual void Mediate(const TCHAR* message, Colleague* sender) = 0;
};
 
//------------------------------------------------------------------
// Colleague 인터페이스
class Colleague
{
public:
    Colleague(Mediator* m) : pMediator(m) { pMediator->AddColleague(this); }
 
public:
    void SendMessages(const TCHAR* str)
    {
        pMediator->Mediate(str, this);
        cout << "Message: " << str << ", Sent by: " << GetName() << endl;
    }
 
    void ReceiveMessages(const TCHAR* str)
    {
        cout << "Message: " << str << ", Recv by: " << GetName() << endl;
    }
 
    virtual const TCHAR* GetName() = 0;
 
protected:
    Mediator* pMediator;
};
 
//------------------------------------------------------------------
// ConcreteColleague1 상속 클래스
class ConcreteColleague1 : public Colleague
{
public:
    ConcreteColleague1(Mediator* m) : Colleague(m) {}
    const TCHAR* GetName() { return typeid(this).name(); }
};
 
//------------------------------------------------------------------
// ConcreteColleague2 상속 클래스
class ConcreteColleague2 : public Colleague
{
public:
    ConcreteColleague2(Mediator* m) : Colleague(m) {}
    const TCHAR* GetName() { return typeid(this).name(); }
};
 
//------------------------------------------------------------------
// ConcreteMediator 상속 클래스
class ConcreteMediator : public Mediator
{
public:
    void AddColleague(Colleague* colleague) 
    {
        mList.push_back(colleague);
    }
 
    void Mediate(const TCHAR* message, Colleague* sender)
    {
        for (Colleague* object : mList)
        {
            if (object != sender)
                object->ReceiveMessages(message);
        }
    }
 
private:
    list<Colleague*> mList;
};
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    ConcreteMediator mConcreteMediator;
 
    ConcreteColleague1 mConcreteColleague1(&mConcreteMediator);
    ConcreteColleague2 mConcreteColleague2(&mConcreteMediator);
 
    mConcreteColleague1.SendMessages("First Message...");
    mConcreteColleague2.SendMessages("Second Message....");
 
    return 0;
}





예제를 통한 중재자 패턴(Mediator Pattern) 알아보기



예제) 중재자 패턴을 활용한 채팅 예제



채팅 중재자 클래스를 만들고 유저클래스들을 리스트 컨테이너에서 통합 관리한다. 유저가 메시지 전송을 하게 되면 중재자 클래스에서 자신을 제외한 등록된 모든 유저들에게 메시지를 전송한다.



예제 코드)

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <list>
 
#if _UNICODE
typedef wstring tstring;
#else
typedef string tstring;
#endif
 
 
//------------------------------------------------------------------
// Mediator 인터페이스
class Colleague;    // 전방 선언
class Mediator
{
public:
    virtual void AppendUser(Colleague* colleague) = 0;
    virtual void RemoveUser(Colleague* colleague) = 0;
    virtual void sendMessage(const TCHAR* message, Colleague* sender) = 0;
};
 
//------------------------------------------------------------------
// Colleague 인터페이스
class Colleague
{
public:
    Colleague(Mediator* m, const TCHAR* name) : pMediator(m), mName(name) {}
 
public:
    virtual void SendMessages(const TCHAR* str) = 0;
    virtual void ReceiveMessages(const TCHAR* str) = 0;
 
protected:
    Mediator* pMediator;
    tstring mName;
};
 
//------------------------------------------------------------------
// User 상속 클래스
class User : public Colleague
{
public:
    User(Mediator* m, const TCHAR* name) : Colleague(m, name) {}
    
public:
    void SendMessages(const TCHAR* str) override
    {
        cout << mName << " send : " << str << endl;
        pMediator->sendMessage(str, this);
    }
 
    void ReceiveMessages(const TCHAR* str) override
    {
        cout << mName << " recv : " << str << endl;
    }
};
 
//------------------------------------------------------------------
// ChatMediator 상속 클래스
class ChatMediator : public Mediator
{
public:
    void AppendUser(Colleague* colleague) override
    {
        mList.push_back(colleague);
    }
 
    void RemoveUser(Colleague* colleague) override
    {
        mList.remove(colleague);
    }
 
    void sendMessage(const TCHAR* message, Colleague* sender)
    {
        for (Colleague* object : mList)
        {
            if (object != sender)
                object->ReceiveMessages(message);
        }
    }
 
private:
    list<Colleague*> mList;
};
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    ChatMediator mChatMediator;
 
    User mUser1(&mChatMediator, "홍길동");
    User mUser2(&mChatMediator, "나이스");
    User mUser3(&mChatMediator, "디자인");
 
    mChatMediator.AppendUser(&mUser1);
    mChatMediator.AppendUser(&mUser2);
    mChatMediator.AppendUser(&mUser3);
 
    mUser1.SendMessages("안녕하세요. 홍길동입니다!");
 
    return 0;
}


예제 결과)