-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMediator.cpp
More file actions
179 lines (156 loc) · 5.95 KB
/
Mediator.cpp
File metadata and controls
179 lines (156 loc) · 5.95 KB
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Mediator is a behavioral design pattern that lets you reduce chaotic dependencies between objects.
// The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.
// Usage examples: The most popular usage of the Mediator pattern in C++ code is facilitating communications between GUI components of an app.
// The synonym of the Mediator is the `Controller` part of MVC pattern.
// Appicability:
// (*) when your collection has a complex data structure under the hood, but you want to hide its complexity from clients (either for convenience or security reasons).
// (**) when you can’t reuse a component in a different program because it’s too dependent on other components.
// (***) when you find yourself creating tons of component subclasses just to reuse some basic behavior in various contexts.
// UML: docs/uml/patterns_behavioral_mediator.drawio.svg
#include <iostream>
#include <string>
#include <vector>
namespace
{
namespace Mediator
{
enum class Event
{
CREATE = 0,
READ,
UPDATE,
DELETE,
};
static inline const char *getEventName(const Event &e)
{
switch (e)
{
case Event::CREATE:
return "CREATE";
case Event::READ:
return "READ";
case Event::UPDATE:
return "UPDATE";
case Event::DELETE:
return "DELETE";
}
return "invalid_event";
}
class IComponent
{
public:
virtual ~IComponent() = default;
virtual void send(const Event e) = 0;
virtual void receive(const Event e) = 0;
};
/**
* The Mediator interface declares methods of communication with components, which usually include just a single notification method.
* Components may pass any context as arguments of this method, including their own objects,
* but only in such a way that no coupling occurs between a receiving component and the sender’s class.
*/
class IMediator
{
public:
virtual ~IMediator() = default;
virtual void registerComponent(IComponent *const c) = 0;
virtual void notify(IComponent *sender, const Event &e) = 0;
};
/**
* Concrete Mediators implement cooperative behavior by coordinating several components.
* Concrete mediators often keep references to all components they manage and sometimes even manage their lifecycle.
*/
class ComponentMediator : public IMediator
{
private:
std::vector<IComponent *> m_components;
public:
void registerComponent(IComponent *const c) override
{
m_components.push_back(c);
}
void notify(IComponent *const sender, const Event &e) override
{
for (auto c : m_components)
{
if (c != sender)
{
c->receive(e);
}
}
}
};
/**
* Components are various classes that contain some business logic.
* Each component has a reference to a mediator, declared with the type of the mediator interface.
* The component isn’t aware of the actual class of the mediator, so you can reuse the component in other programs by linking it to a different mediator.
*/
class AbstractComponent : public IComponent
{
private:
const std::string m_id;
protected:
IMediator *m_mediator;
void log(const Event &e, const std::string &msg) const
{
std::cout << "\t" + msg + "-id:" + m_id + "-event:" + getEventName(e) + "\n";
}
public:
explicit AbstractComponent(const std::string &id, IMediator *const m = nullptr) : m_id{id}, m_mediator{m} {};
};
/**
* Concrete Components implement various functionality. They don't depend on
* other components. They also don't depend on any concrete mediator classes.
*/
class ConreteComponent : public AbstractComponent
{
public:
explicit ConreteComponent(const std::string &id, IMediator *const m = nullptr) : AbstractComponent{id, m} {}
void send(const Event e) override
{
log(e, "[SEND]");
if (m_mediator != nullptr)
m_mediator->notify(this, e);
}
void receive(const Event e) override
{
log(e, "[RECV]");
// Additional handling logic can go here
}
};
namespace Client
{
void clientCode(IComponent *comp)
{
comp->send(Event::READ);
}
}
void run()
{
IMediator *mediator = new ComponentMediator();
IComponent *c1 = new ConreteComponent("1763700876", mediator);
IComponent *c2 = new ConreteComponent("1763700882", mediator);
IComponent *c3 = new ConreteComponent("1763700899", mediator);
IComponent *c4 = new ConreteComponent("1763700900", mediator);
// Only c1, c3, c4 receive notifications.
mediator->registerComponent(c1);
mediator->registerComponent(c3);
mediator->registerComponent(c4);
// c2 triggers event => observed by others
Client::clientCode(c2);
delete mediator;
delete c1;
delete c2;
delete c3;
delete c4;
}
}
}
struct MediatorAutoRunner
{
MediatorAutoRunner()
{
std::cout << "\n--- Mediator Pattern Example ---\n";
Mediator::run();
}
};
static MediatorAutoRunner instance;