Skip to content

Commit b6e966d

Browse files
Eder DuranEder Duran
authored andcommitted
Composite Example
1 parent 2ad64be commit b6e966d

File tree

2 files changed

+272
-0
lines changed

2 files changed

+272
-0
lines changed

src/Composite/Conceptual/Output.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Client: I've got a simple component:
2+
RESULT: Leaf
3+
4+
Client: Now I've got a composite tree:
5+
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))
6+
7+
Client: I don't need to check the components classes even when managing the tree:
8+
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
9+

src/Composite/Conceptual/main.cc

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
2+
#include <iostream>
3+
#include <string>
4+
#include <list>
5+
#include <algorithm>
6+
/**
7+
* EN: Composite Design Pattern
8+
*
9+
* Intent: Lets you compose objects into tree structures and then work with
10+
* these structures as if they were individual objects.
11+
*
12+
* RU: Паттерн Компоновщик
13+
*
14+
* Назначение: Позволяет сгруппировать объекты в древовидную структуру, а затем
15+
* работать с ними так, как будто это единичный объект.
16+
*/
17+
/**
18+
* EN: The base Component class declares common operations for both simple and
19+
* complex objects of a composition.
20+
*
21+
* RU: Базовый класс Компонент объявляет общие операции как для простых, так и
22+
* для сложных объектов структуры.
23+
*/
24+
class Component
25+
{
26+
/**
27+
* @var Component
28+
*/
29+
protected:
30+
Component *parent_;
31+
/**
32+
* EN: Optionally, the base Component can declare an interface for setting
33+
* and accessing a parent of the component in a tree structure. It can also
34+
* provide some default implementation for these methods.
35+
*
36+
* RU: При необходимости базовый Компонент может объявить интерфейс для
37+
* установки и получения родителя компонента в древовидной структуре. Он
38+
* также может предоставить некоторую реализацию по умолчанию для этих
39+
* методов.
40+
*/
41+
public:
42+
virtual ~Component() {}
43+
void SetParent(Component *parent)
44+
{
45+
this->parent_ = parent;
46+
}
47+
Component *GetParent() const
48+
{
49+
return this->parent_;
50+
}
51+
/**
52+
* EN: In some cases, it would be beneficial to define the child-management
53+
* operations right in the base Component class. This way, you won't need to
54+
* expose any concrete component classes to the client code, even during the
55+
* object tree assembly. The downside is that these methods will be empty
56+
* for the leaf-level components.
57+
*
58+
* RU: В некоторых случаях целесообразно определить операции управления
59+
* потомками прямо в базовом классе Компонент. Таким образом, вам не нужно
60+
* будет предоставлять конкретные классы компонентов клиентскому коду, даже
61+
* во время сборки дерева объектов. Недостаток такого подхода в том, что эти
62+
* методы будут пустыми для компонентов уровня листа.
63+
*/
64+
virtual void Add(Component *component) {}
65+
virtual void Remove(Component *component) {}
66+
/**
67+
* EN: You can provide a method that lets the client code figure out whether
68+
* a component can bear children.
69+
*
70+
* RU: Вы можете предоставить метод, который позволит клиентскому коду
71+
* понять, может ли компонент иметь вложенные объекты.
72+
*/
73+
virtual bool IsComposite() const
74+
{
75+
return false;
76+
}
77+
/**
78+
* EN: The base Component may implement some default behavior or leave it to
79+
* concrete classes (by declaring the method containing the behavior as
80+
* "abstract").
81+
*
82+
* RU: Базовый Компонент может сам реализовать некоторое поведение по
83+
* умолчанию или поручить это конкретным классам, объявив метод, содержащий
84+
* поведение абстрактным.
85+
*/
86+
virtual std::string Operation() const = 0;
87+
};
88+
/**
89+
* EN: The Leaf class represents the end objects of a composition. A leaf can't
90+
* have any children.
91+
*
92+
* Usually, it's the Leaf objects that do the actual work, whereas Composite
93+
* objects only delegate to their sub-components.
94+
*
95+
* RU: Класс Лист представляет собой конечные объекты структуры. Лист не может
96+
* иметь вложенных компонентов.
97+
*
98+
* Обычно объекты Листьев выполняют фактическую работу, тогда как объекты
99+
* Контейнера лишь делегируют работу своим подкомпонентам.
100+
*/
101+
class Leaf : public Component
102+
{
103+
public:
104+
std::string Operation() const override
105+
{
106+
return "Leaf";
107+
}
108+
};
109+
/**
110+
* EN: The Composite class represents the complex components that may have
111+
* children. Usually, the Composite objects delegate the actual work to their
112+
* children and then "sum-up" the result.
113+
*
114+
* RU: Класс Контейнер содержит сложные компоненты, которые могут иметь
115+
* вложенные компоненты. Обычно объекты Контейнеры делегируют фактическую работу
116+
* своим детям, а затем «суммируют» результат.
117+
*/
118+
class Composite : public Component
119+
{
120+
/**
121+
* @var \SplObjectStorage
122+
*/
123+
protected:
124+
std::list<Component *> children_;
125+
126+
public:
127+
/**
128+
* EN: A composite object can add or remove other components (both simple or
129+
* complex) to or from its child list.
130+
*
131+
* RU: Объект контейнера может как добавлять компоненты в свой список
132+
* вложенных компонентов, так и удалять их, как простые, так и сложные.
133+
*/
134+
void Add(Component *component) override
135+
{
136+
this->children_.push_back(component);
137+
component->SetParent(this);
138+
}
139+
/**
140+
* EN: Have in mind that this method removes the pointer to the list but doesn't frees the
141+
* memory, you should do it manually or better use smart pointers.
142+
*
143+
* RU:
144+
*/
145+
void Remove(Component *component) override
146+
{
147+
148+
children_.remove(component);
149+
component->SetParent(nullptr);
150+
}
151+
bool IsComposite() const override
152+
{
153+
return true;
154+
}
155+
/**
156+
* EN: The Composite executes its primary logic in a particular way. It
157+
* traverses recursively through all its children, collecting and summing
158+
* their results. Since the composite's children pass these calls to their
159+
* children and so forth, the whole object tree is traversed as a result.
160+
*
161+
* RU: Контейнер выполняет свою основную логику особым образом. Он проходит
162+
* рекурсивно через всех своих детей, собирая и суммируя их результаты.
163+
* Поскольку потомки контейнера передают эти вызовы своим потомкам и так
164+
* далее, в результате обходится всё дерево объектов.
165+
*/
166+
std::string Operation() const override
167+
{
168+
std::string result;
169+
for (const Component *c : children_)
170+
{
171+
if (c == children_.back())
172+
{
173+
result += c->Operation();
174+
}
175+
else
176+
{
177+
result += c->Operation() + "+";
178+
}
179+
}
180+
return "Branch(" + result + ")";
181+
}
182+
};
183+
/**
184+
* EN: The client code works with all of the components via the base interface.
185+
*
186+
* RU: Клиентский код работает со всеми компонентами через базовый интерфейс.
187+
*/
188+
void ClientCode(Component *component)
189+
{
190+
// ...
191+
std::cout << "RESULT: " << component->Operation();
192+
// ...
193+
}
194+
195+
/**
196+
* EN: Thanks to the fact that the child-management operations are declared in
197+
* the base Component class, the client code can work with any component, simple
198+
* or complex, without depending on their concrete classes.
199+
*
200+
* RU: Благодаря тому, что операции управления потомками объявлены в базовом
201+
* классе Компонента, клиентский код может работать как с простыми, так и со
202+
* сложными компонентами, вне зависимости от их конкретных классов.
203+
*/
204+
void ClientCode2(Component *component1, Component *component2)
205+
{
206+
// ...
207+
if (component1->IsComposite())
208+
{
209+
component1->Add(component2);
210+
}
211+
std::cout << "RESULT: " << component1->Operation();
212+
// ...
213+
}
214+
215+
/**
216+
* EN: This way the client code can support the simple leaf components...
217+
*
218+
* RU: Таким образом, клиентский код может поддерживать простые
219+
* компоненты-листья...
220+
*/
221+
222+
int main()
223+
{
224+
Component *simple = new Leaf;
225+
std::cout << "Client: I've got a simple component:\n";
226+
ClientCode(simple);
227+
std::cout << "\n\n";
228+
/**
229+
* EN: ...as well as the complex composites.
230+
*
231+
* RU: ...а также сложные контейнеры.
232+
*/
233+
234+
Component *tree = new Composite;
235+
Component *branch1 = new Composite;
236+
237+
Component *leaf_1 = new Leaf;
238+
Component *leaf_2 = new Leaf;
239+
Component *leaf_3 = new Leaf;
240+
branch1->Add(leaf_1);
241+
branch1->Add(leaf_2);
242+
Component *branch2 = new Composite;
243+
branch2->Add(leaf_3);
244+
tree->Add(branch1);
245+
tree->Add(branch2);
246+
std::cout << "Client: Now I've got a composite tree:\n";
247+
ClientCode(tree);
248+
std::cout << "\n\n";
249+
250+
std::cout << "Client: I don't need to check the components classes even when managing the tree:\n";
251+
ClientCode2(tree, simple);
252+
std::cout << "\n";
253+
254+
delete simple;
255+
delete tree;
256+
delete branch1;
257+
delete branch2;
258+
delete leaf_1;
259+
delete leaf_2;
260+
delete leaf_3;
261+
262+
return 0;
263+
}

0 commit comments

Comments
 (0)