Skip to content

Commit 176f893

Browse files
committed
[DECORATOR]: Added ressources and example code for Decorator pattern.
1 parent 1305871 commit 176f893

File tree

3 files changed

+177
-2
lines changed

3 files changed

+177
-2
lines changed
Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,58 @@
1-
# TODO
1+
Also known as **Wrapper**.
22

3-
Stay tuned, this section will be completed shortly !
3+
# Intend
4+
5+
**Dynamically attach responsabilities to an object**.
6+
7+
It provides a flexible alternative to subclassing for extending functionality.
8+
9+
You should use the _Decorator_ pattern in the following cases :
10+
- You want to **provide individual objects** (not an entire class) **with a new behaviour**.
11+
- You want to **add responsabilities _dynamically_ and _transparently_**.
12+
- When the alternative (_extension by subclassing_) is impractical :
13+
- When it would produce an explosion of subclasses to support every combination.
14+
- The class definition is hidden or unavailable for subclassing.
15+
16+
# How it's done
17+
18+
![UML](UML.jpg)
19+
20+
**Participants**
21+
22+
- _Component_ : The interface for objects that can have responsabilities dynamically added.
23+
- _ConcreteComponent_ : The objects to which responsabilities can be added.
24+
- _Decorator_ : Defines an interface that conforms to _Component_'s interface.
25+
Maintain a reference to a _Component_ object (_wrappee_).
26+
- _ConcreteDecorator_ : The object that adds responsabilities to _ConcreteComponent_.
27+
28+
**How to implement**
29+
30+
1. **Create an interface** and declare the methods common to both the primary _Component_ and the optional layers.
31+
2. **Create your _ConcreteComponent_** class with its base behaviour.
32+
3. **Create your _Decorator_** class with a field storing a reference to the wrapped object (Your _Component_). The _Decorator_ will delegate all the work (i.e. except for the additional responsabilities) to the wrapped object.
33+
4. **Create your _ConcreteDecorator_** and implement the additional responsabilities before or after the call to the _wrappee_ behaviour.
34+
35+
Note : The _Client_ can then **create and compose _ConcreteDecorators_** in the way he needs.
36+
37+
Note : UML class diagram taken from [**here**](https://upload.wikimedia.org/wikipedia/commons/8/83/W3sDesign_Decorator_Design_Pattern_UML.jpg)
38+
39+
# Pros & cons
40+
41+
**Pros**
42+
43+
- **Extend** an object's behaviour without subclassing.
44+
- **Add responsabilities at runtime**.
45+
- **Combine behaviours** (decorators composition) to suit your needs.
46+
- **Single responsability principle** : Divide monolithic classes into many classes with unique responsabilities.
47+
48+
49+
**Cons**
50+
51+
- It is hard to **remove a decorator** once it has been added.
52+
- **Order** : It might be difficult to implement decorators in a way they are order-independant.
53+
54+
# Notes
55+
56+
Here are some _usefull ressources_ :
57+
- A [Refactoring guru](https://refactoring.guru/design-patterns/decorator) article.
58+
- A complete example [here](https://www.bogotobogo.com/DesignPatterns/decorator.php)

structural-patterns/decorator/UML.jpg

49.5 KB
Loading
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Rewritten example - Original here
2+
// https://en.wikipedia.org/wiki/Decorator_pattern#UML_class_and_sequence_diagram
3+
4+
#include <memory>
5+
#include <iostream>
6+
#include <string>
7+
8+
/*!
9+
* @brief : Component - defines the interface of the
10+
* objects you want to provide additional layers
11+
* of behaviours to.
12+
*/
13+
class WebPage
14+
{
15+
public:
16+
virtual void display(void) const = 0;
17+
virtual ~WebPage() = default;
18+
};
19+
20+
/*!
21+
* @brief : ConcreteComponent - The objects you want to
22+
* be able to add responsabilities to.
23+
*/
24+
class BasicWebPage : public WebPage
25+
{
26+
public:
27+
void display(void) const override { std::cout << "Basic WEB page" << std::endl; }
28+
29+
BasicWebPage(std::string&& p_html = "") : m_html(p_html) {}
30+
~BasicWebPage()=default;
31+
32+
private:
33+
std::string m_html;
34+
};
35+
36+
/*!
37+
* @brief : Decorator - Interface that conforms to WebPage interface
38+
* Keep a reference (in that case a std::unique_ptr) on the
39+
* WebPage object.
40+
*/
41+
class WebPageDecorator : public WebPage
42+
{
43+
public:
44+
WebPageDecorator(std::unique_ptr<WebPage> webPage): _webPage(std::move(webPage)) {}
45+
~WebPageDecorator()=default;
46+
47+
/*!
48+
* @brief : Note that the "basic behaviour" is still realized by the wrappee.
49+
*/
50+
void display(void) const override { _webPage->display(); }
51+
52+
private:
53+
std::unique_ptr<WebPage> _webPage;
54+
};
55+
56+
/*!
57+
* @brief : ConcreteDecorator1 - Implements the new behaviour
58+
* added to the wrappee.
59+
*/
60+
class AuthenticatedWebPage : public WebPageDecorator
61+
{
62+
public:
63+
AuthenticatedWebPage(std::unique_ptr<WebPage> webPage):
64+
WebPageDecorator(std::move(webPage)) {}
65+
~AuthenticatedWebPage()=default;
66+
67+
/*!
68+
* @brief : New behaviour enhanced by the ConcreteDecorator
69+
*/
70+
void display(void) const override
71+
{
72+
// Could be in any order
73+
authenticateUser();
74+
WebPageDecorator::display();
75+
}
76+
77+
private:
78+
void authenticateUser(void) const { std::cout << "authentification done" << std::endl; }
79+
};
80+
81+
/*!
82+
* @brief : ConcreteDecorator2 - Implements the new behaviour
83+
* added to the wrappee.
84+
*/
85+
class AuthorizedWebPage : public WebPageDecorator
86+
{
87+
public:
88+
AuthorizedWebPage(std::unique_ptr<WebPage> webPage):
89+
WebPageDecorator(std::move(webPage)) {}
90+
~AuthorizedWebPage()=default;
91+
92+
void display(void) const override
93+
{
94+
// Once again, could be in any order
95+
WebPageDecorator::display();
96+
authorizedUser();
97+
}
98+
99+
private:
100+
void authorizedUser(void) const { std::cout << "authorized done" << std::endl; }
101+
};
102+
103+
int main()
104+
{
105+
std::unique_ptr<WebPage> myPage = std::make_unique<BasicWebPage>();
106+
std::cout << " --- ConcreteComponent --- " << std::endl;
107+
myPage->display();
108+
109+
myPage = std::make_unique<AuthorizedWebPage >(std::move(myPage));
110+
std::cout << " --- Added ConcreteDecorator1 --- " << std::endl;
111+
myPage->display();
112+
113+
myPage = std::make_unique<AuthenticatedWebPage>(std::move(myPage));
114+
std::cout << " --- Added ConcreteDecorator2 --- " << std::endl;
115+
myPage->display();
116+
117+
std::cout << std::endl;
118+
119+
return 0;
120+
}

0 commit comments

Comments
 (0)