-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathConceptualExample.cpp
More file actions
246 lines (200 loc) · 7.29 KB
/
ConceptualExample.cpp
File metadata and controls
246 lines (200 loc) · 7.29 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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
// ===========================================================================
// ConceptualExample.cpp - Decorator Pattern
// ===========================================================================
#include <iostream>
#include <memory>
#include <string>
/**
* The base Component interface defines operations
* that can be altered by decorators.
*/
class IComponent {
public:
virtual ~IComponent() = default;
virtual std::string operation() const = 0;
};
/**
* Concrete Components provide default implementations of the operation(s).
* There might be several variations of these classes.
*/
class ConcreteComponent final : public IComponent {
public:
std::string operation() const override {
return "CONCRETE COMPONENT";
}
};
// ---------------------------------------------------------------------------
/**
* The base Decorator class follows the same interface as the concrete components.
* The primary purpose of this class is to define the wrapping interface for all
* concrete decorators. The default implementation of the wrapping code might
* include a field for storing a wrapped component and the means to initialize it.
*/
class DecoratorBase : public IComponent {
protected:
std::shared_ptr<IComponent> m_component;
public:
DecoratorBase(const std::shared_ptr<IComponent>& component)
: m_component{ component }
{}
/**
* The Decorator delegates all work to the wrapped component.
*/
std::string operation() const override {
if (!m_component) {
return std::string{};
}
return m_component->operation();
}
};
// ---------------------------------------------------------------------------
/**
* Concrete Decorators call the wrapped object and alter its result in some way.
*/
class ConcreteDecoratorA final : public DecoratorBase {
/**
* Decorators may call parent implementation of the operation, instead of
* calling the wrapped object directly. This approach simplifies extension of
* decorator classes.
*/
public:
ConcreteDecoratorA(const std::shared_ptr<IComponent>& component)
: DecoratorBase{ component }
{}
std::string operation() const override {
std::string parentResult{ DecoratorBase::operation() };
std::string decoratedResult{ "ConcreteDecoratorA ( " + parentResult + " )" };
return decoratedResult;
}
};
/**
* Decorators can execute their behavior either before or after
* the call to a wrapped object.
*/
class ConcreteDecoratorB final : public DecoratorBase {
public:
ConcreteDecoratorB(const std::shared_ptr<IComponent>& component)
: DecoratorBase{ component }
{}
std::string operation() const override {
std::string parentResult{ DecoratorBase::operation() };
std::string decoratedResult{ "ConcreteDecoratorB [ " + parentResult + " ]" };
return decoratedResult;
}
};
/**
* Need one more Decorator class to demonstrate nested execution of decorator objects
*/
class ConcreteDecoratorC final : public DecoratorBase {
public:
ConcreteDecoratorC(const std::shared_ptr<IComponent>& component)
: DecoratorBase{ component }
{}
std::string operation() const override {
std::string parentResult{ DecoratorBase::operation() };
std::string decoratedResult{ "ConcreteDecoratorC { " + parentResult + " }" };
return decoratedResult;
}
};
// ---------------------------------------------------------------------------
/**
* The client code works only with objects using the Component interface.
* This way it can stay independent of the concrete classes of components
* it works with.
*/
static void clientCode(const std::shared_ptr<IComponent>& component) {
// ...
std::cout << "Result: " << component->operation();
// ...
}
void test_conceptual_example_01() {
/**
* This way the client code can support both simple components ...
*/
std::shared_ptr<IComponent> component{
std::make_shared<ConcreteComponent>()
};
std::cout << "Client: I've got a simple component:\n";
clientCode(component);
std::cout << std::endl << std::endl;
}
void test_conceptual_example_02() {
/**
* ...as well as decorated ones ...
*
* Note how decorators can wrap not only simple components
* but the other decorators as well.
*/
std::shared_ptr<IComponent> component{
std::make_shared<ConcreteComponent>()
};
std::shared_ptr<IComponent> decorator1{
std::make_shared<ConcreteDecoratorA>(component)
};
std::shared_ptr<IComponent> decorator2{
std::make_shared<ConcreteDecoratorB>(decorator1)
};
std::cout << "Client: Decorated component:" << std::endl;
clientCode(decorator2);
std::cout << std::endl << std::endl;
// --------------------------------------------------------------
/**
* Same as before - written in a more compact syntax:
* Nested usage of decorator objects
*/
std::shared_ptr<IComponent> decorator {
std::make_shared<ConcreteDecoratorB>(
std::make_shared<ConcreteDecoratorA>(component)
)
};
std::cout << "Client: Same decorated component - written in a more compact syntax:" << std::endl;
clientCode(decorator);
std::cout << std::endl << std::endl;
// --------------------------------------------------------------
/**
* One more Demonstration of nested use of decorator objects
*/
decorator =
std::make_shared<ConcreteDecoratorA>(
std::make_shared<ConcreteDecoratorB>(
std::make_shared<ConcreteDecoratorC>(component)));
std::cout << "Client: Decorated component using three decorator objects:" << std::endl;
clientCode(decorator);
std::cout << std::endl << std::endl;
// --------------------------------------------------------------
/**
* Demonstrate reverse Decoration
*/
decorator =
std::make_shared<ConcreteDecoratorC>(
std::make_shared<ConcreteDecoratorB>(
std::make_shared<ConcreteDecoratorA>(component)));
std::cout << "Client: Reverse Decoration:" << std::endl;
clientCode(decorator);
std::cout << std::endl;
}
void test_conceptual_example_03() {
/**
* ... and at the very end: changing decorators at runtime
*/
// component which is going to be decorated
std::shared_ptr<IComponent> component{ std::make_shared<ConcreteComponent>() };
// run-time dependent decorator
std::shared_ptr<IComponent> decorator;
if (true) // <== change 'true' to 'false'
{
std::shared_ptr<IComponent> decorator1{ std::make_shared<ConcreteDecoratorA>(component) };
decorator = std::make_shared<ConcreteDecoratorB>(decorator1);
std::cout << "Client: Now I've this decorated component (if):" << std::endl;
}
else {
std::shared_ptr<IComponent> decorator1 {std::make_shared<ConcreteDecoratorB>(component)};
decorator = std::make_shared<ConcreteDecoratorA>(decorator1);
std::cout << "Client: Now I've that decorated component (else):" << std::endl;
}
clientCode(decorator);
std::cout << std::endl << std::endl;
}
// ===========================================================================
// End-of-File
// ===========================================================================