1+ // Decorator is a structural design pattern that lets you attach new behaviors to objects
2+ // by placing these objects inside special wrapper objects that contain the behaviors.
3+ // Appicability:
4+ // (*) when you need to be able to assign extra behaviors to objects at runtime without breaking the code that uses these objects.
5+ // (**) when it’s awkward or not possible to extend an object’s behavior using inheritance.
6+ // UML: docs/uml/patterns_structural_decorator.drawio.svg
7+
8+ #include < iostream>
9+ #include < string>
10+ #include < list>
11+ #include < algorithm>
12+
13+ namespace
14+ {
15+ namespace Problem
16+ {
17+
18+ class IComponent
19+ {
20+ public:
21+ virtual ~IComponent () {}
22+ virtual std::string operation () const = 0;
23+ };
24+
25+ class ConcreteComponent : public IComponent
26+ {
27+ public:
28+ std::string operation () const override
29+ {
30+ return " ConcreteComponent" ;
31+ }
32+ };
33+
34+ class ComponentWithA : public ConcreteComponent
35+ {
36+ public:
37+ std::string operation () const override
38+ {
39+ return ConcreteComponent::operation () + " + FeatureA" ;
40+ }
41+ };
42+
43+ class ComponentWithB : public ConcreteComponent
44+ {
45+ public:
46+ std::string operation () const override
47+ {
48+ return ConcreteComponent::operation () + " + FeatureB" ;
49+ }
50+ };
51+
52+ class ComponentWithAandB : public ConcreteComponent
53+ {
54+ public:
55+ std::string operation () const override
56+ {
57+ return ConcreteComponent::operation () + " + FeatureA + FeatureB" ;
58+ }
59+ };
60+
61+ // [P1]
62+ // If you have 3 features , e.g FeatureC -> many combinations
63+ // If you have 5 features -> 32 subclasses
64+
65+ namespace Client
66+ {
67+ void clientCode (const IComponent &comp)
68+ {
69+ std::cout << comp.operation () << " \n " ;
70+ }
71+ }
72+
73+ void run ()
74+ {
75+ std::cout << " \n\n Problem\n " ;
76+ IComponent *simple = new ConcreteComponent;
77+ Client::clientCode (*simple);
78+
79+ IComponent *withA = new ComponentWithA;
80+ Client::clientCode (*withA);
81+
82+ IComponent *withB = new ComponentWithB;
83+ Client::clientCode (*withB);
84+
85+ IComponent *withAB = new ComponentWithAandB;
86+ Client::clientCode (*withAB);
87+
88+ delete simple;
89+ delete withA;
90+ delete withB;
91+ delete withAB;
92+ }
93+
94+ }
95+
96+ namespace DecoratorPattern
97+ {
98+ class IComponent
99+ {
100+ public:
101+ virtual ~IComponent () {}
102+ virtual std::string operation () const = 0;
103+ };
104+
105+ /* *
106+ * Concrete Component
107+ * - is a class of objects being wrapped.
108+ * - defines the basic behavior, which can be altered by decorators.
109+ */
110+ class ConcreteComponent : public IComponent
111+ {
112+ public:
113+ std::string operation () const override
114+ {
115+ return " ConcreteComponent" ;
116+ }
117+ };
118+
119+ /* *
120+ * The base Decorator class follows the same interface as the other components.
121+ * - has a field for referencing a wrapped object.
122+ * - the field’s type should be declared as the component interface so it can contain both concrete components and decorators.
123+ * - the base decorator delegates all operations to the wrapped object.
124+ */
125+ class BaseDecorator : public IComponent
126+ {
127+ protected:
128+ IComponent *m_component;
129+
130+ public:
131+ explicit BaseDecorator (IComponent *component) : m_component{component} {}
132+
133+ /* *
134+ * The Decorator delegates all work to the wrapped component.
135+ */
136+ std::string operation () const override
137+ {
138+ return m_component->operation ();
139+ }
140+ };
141+
142+ /* *
143+ * Concrete Decorators :
144+ * - call the wrapped object and alter its result in some way.
145+ * - define extra behaviors that can be added to components dynamically.
146+ * - override methods of the base decorator and execute their behavior either before
147+ * or after calling the parent method.
148+ */
149+ class ConcreteDecoratorA : public BaseDecorator
150+ {
151+ public:
152+ explicit ConcreteDecoratorA (IComponent *component) : BaseDecorator{component} {}
153+
154+ std::string operation () const override
155+ {
156+ return BaseDecorator::operation () + " + FeatureA" ;
157+ }
158+ };
159+
160+ class ConcreteDecoratorB : public BaseDecorator
161+ {
162+ public:
163+ explicit ConcreteDecoratorB (IComponent *component) : BaseDecorator{component} {}
164+
165+ std::string operation () const override
166+ {
167+ return BaseDecorator::operation () + " + FeatureB" ;
168+ }
169+ };
170+
171+ class ConcreteDecoratorC : public BaseDecorator
172+ {
173+ public:
174+ explicit ConcreteDecoratorC (IComponent *component) : BaseDecorator{component} {}
175+
176+ std::string operation () const override
177+ {
178+ return BaseDecorator::operation () + " + FeatureC" ;
179+ }
180+ };
181+
182+ namespace Client
183+ {
184+ void clientCode (const IComponent &comp)
185+ {
186+ std::cout << comp.operation () << " \n " ;
187+ }
188+ }
189+
190+ void run ()
191+ {
192+ std::cout << " \n\n Decorator\n " ;
193+ IComponent *simple = new ConcreteComponent;
194+ Client::clientCode (*simple);
195+
196+ IComponent *withA = new ConcreteDecoratorA (simple);
197+ Client::clientCode (*withA);
198+
199+ IComponent *withB = new ConcreteDecoratorB (simple);
200+ Client::clientCode (*withB);
201+
202+ IComponent *withAB = new ConcreteDecoratorB (withA);
203+ Client::clientCode (*withAB);
204+
205+ IComponent *withABC = new ConcreteDecoratorC (withAB);
206+ Client::clientCode (*withABC);
207+
208+ delete simple;
209+ delete withA;
210+ delete withB;
211+ delete withAB;
212+ delete withABC;
213+ }
214+ }
215+
216+ }
217+
218+ struct DecoratorAutoRuner
219+ {
220+ DecoratorAutoRuner ()
221+ {
222+ std::cout << " \n --- Decorator Pattern Example ---\n " ;
223+ Problem::run ();
224+ DecoratorPattern::run ();
225+ }
226+ };
227+
228+ static DecoratorAutoRuner instance;
0 commit comments