Skip to content

Commit 0b10913

Browse files
committed
Composite: improve conceptual example
1 parent 7922ecf commit 0b10913

File tree

2 files changed

+150
-81
lines changed

2 files changed

+150
-81
lines changed

Composite.Conceptual/Output.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Client: I get a simple component:
2-
RESULT: LEAF
2+
RESULT: Leaf
33

4-
Client: Now I get a composite tree:
5-
RESULT: Branch(Branch(LEAF+LEAF)+Branch(LEAF))
4+
Client: Now I've got a composite tree:
5+
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))
66

7-
Client: I can merge two components without checking their classes:
8-
RESULT: Branch(Branch(LEAF+LEAF)+Branch(LEAF)+LEAF)
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)

Composite.Conceptual/Program.cs

Lines changed: 145 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,193 @@
1-
using System;
1+
// EN: Composite Design Pattern
2+
//
3+
// Intent: Compose objects into tree structures to represent part-whole
4+
// hierarchies. Composite lets clients treat individual objects and compositions
5+
// of objects uniformly.
6+
//
7+
// RU: Паттерн Компоновщик
8+
//
9+
// Назначение: Объединяет объекты в древовидные структуры для представления
10+
// иерархий часть-целое. Компоновщик позволяет клиентам обрабатывать отдельные
11+
// объекты и группы объектов одинаковым образом.
12+
13+
using System;
214
using System.Collections.Generic;
315

416
namespace RefactoringGuru.DesignPatterns.Composite.Conceptual
517
{
18+
// EN: The base Component class declares common operations for both simple and
19+
// complex objects of a composition.
20+
//
21+
// RU: Базовый класс Компонент объявляет общие операции как для простых, так и
22+
// для сложных объектов структуры.
623
abstract class Component
724
{
825
public Component() { }
926

10-
public abstract void Operation();
11-
12-
public abstract void Add(Component c);
13-
14-
public abstract void Remove(Component c);
15-
16-
public abstract bool IsComposite();
17-
}
18-
19-
class Composite : Component
20-
{
21-
List<Component> children = new List<Component>();
22-
23-
public Composite()
24-
{
25-
26-
}
27-
28-
public override void Add(Component component)
27+
// EN: The base Component may implement some default behavior or leave it to
28+
// concrete classes (by declaring the method containing the behavior as
29+
// "abstract").
30+
//
31+
// RU: Базовый Компонент может сам реализовать некоторое поведение по
32+
// умолчанию или поручить это конкретным классам, объявив метод, содержащий
33+
// поведение абстрактным.
34+
public abstract string Operation();
35+
36+
// EN: In some cases, it would be beneficial to define the child-management
37+
// operations right in the base Component class. This way, you won't need to
38+
// expose any concrete component classes to the client code, even during the
39+
// object tree assembly. The downside is that these methods will be empty
40+
// for the leaf-level components.
41+
//
42+
// RU: В некоторых случаях целесообразно определить операции управления
43+
// потомками прямо в базовом классе Компонент. Таким образом, вам не нужно
44+
// будет предоставлять конкретные классы компонентов клиентскому коду, даже
45+
// во время сборки дерева объектов. Недостаток такого подхода в том, что эти
46+
// методы будут пустыми для компонентов уровня листа.
47+
public virtual void Add(Component component)
2948
{
30-
children.Add(component);
49+
throw new NotImplementedException();
3150
}
3251

33-
public override void Remove(Component component)
52+
public virtual void Remove(Component component)
3453
{
35-
children.Remove(component);
54+
throw new NotImplementedException();
3655
}
3756

38-
public override bool IsComposite()
57+
// EN: You can provide a method that lets the client code figure out whether
58+
// a component can bear children.
59+
//
60+
// RU: Вы можете предоставить метод, который позволит клиентскому коду
61+
// понять, может ли компонент иметь вложенные объекты.
62+
public virtual bool IsComposite()
3963
{
4064
return true;
4165
}
66+
}
4267

43-
public override void Operation()
68+
// EN: The Leaf class represents the end objects of a composition. A leaf can't
69+
// have any children.
70+
//
71+
// Usually, it's the Leaf objects that do the actual work, whereas Composite
72+
// objects only delegate to their sub-components.
73+
//
74+
// RU: Класс Лист представляет собой конечные объекты структуры. Лист не может
75+
// иметь вложенных компонентов.
76+
//
77+
// Обычно объекты Листьев выполняют фактическую работу, тогда как объекты
78+
// Контейнера лишь делегируют работу своим подкомпонентам.
79+
class Leaf : Component
80+
{
81+
public override string Operation()
4482
{
45-
int i = 0;
83+
return "Leaf";
84+
}
4685

47-
Console.Write("Branch(");
48-
foreach (Component component in children)
49-
{
50-
component.Operation();
51-
if (i != children.Count-1)
52-
{
53-
Console.Write("+");
54-
}
55-
i++;
56-
}
57-
Console.Write(")");
86+
public override bool IsComposite()
87+
{
88+
return false;
5889
}
5990
}
6091

61-
class Leaf : Component
92+
// EN: The Composite class represents the complex components that may have
93+
// children. Usually, the Composite objects delegate the actual work to their
94+
// children and then "sum-up" the result.
95+
//
96+
// RU: Класс Контейнер содержит сложные компоненты, которые могут иметь
97+
// вложенные компоненты. Обычно объекты Контейнеры делегируют фактическую работу
98+
// своим детям, а затем «суммируют» результат.
99+
class Composite : Component
62100
{
63-
public Leaf()
101+
protected List<Component> _children = new List<Component>();
102+
103+
public override void Add(Component component)
64104
{
65-
105+
this._children.Add(component);
66106
}
67107

68-
public override void Operation()
108+
public override void Remove(Component component)
69109
{
70-
Console.Write("LEAF");
110+
this._children.Remove(component);
71111
}
72112

73-
public override void Add(Component component)
113+
// EN: The Composite executes its primary logic in a particular way. It
114+
// traverses recursively through all its children, collecting and summing
115+
// their results. Since the composite's children pass these calls to their
116+
// children and so forth, the whole object tree is traversed as a result.
117+
//
118+
// RU: Контейнер выполняет свою основную логику особым образом. Он проходит
119+
// рекурсивно через всех своих детей, собирая и суммируя их результаты.
120+
// Поскольку потомки контейнера передают эти вызовы своим потомкам и так
121+
// далее, в результате обходится всё дерево объектов.
122+
public override string Operation()
74123
{
75-
throw new NotImplementedException();
124+
int i = 0;
125+
string result = "Branch(";
126+
127+
foreach (Component component in this._children)
128+
{
129+
result += component.Operation();
130+
if (i != this._children.Count - 1)
131+
{
132+
result += "+";
133+
}
134+
i++;
135+
}
136+
137+
return result + ")";
76138
}
139+
}
77140

78-
public override void Remove(Component component)
141+
class Client
142+
{
143+
// EN: The client code works with all of the components via the base
144+
// interface.
145+
//
146+
// RU: Клиентский код работает со всеми компонентами через базовый
147+
// интерфейс.
148+
public void ClientCode(Component leaf)
79149
{
80-
throw new NotImplementedException();
150+
Console.WriteLine($"RESULT: {leaf.Operation()}\n");
81151
}
82152

83-
public override bool IsComposite()
153+
// EN: Thanks to the fact that the child-management operations are
154+
// declared in the base Component class, the client code can work with
155+
// any component, simple or complex, without depending on their concrete
156+
// classes.
157+
//
158+
// RU: Благодаря тому, что операции управления потомками объявлены в
159+
// базовом классе Компонента, клиентский код может работать как с
160+
// простыми, так и со сложными компонентами, вне зависимости от их
161+
// конкретных классов.
162+
public void ClientCode2(Component component1, Component component2)
84163
{
85-
return false;
164+
if (component1.IsComposite())
165+
{
166+
component1.Add(component2);
167+
}
168+
169+
Console.WriteLine($"RESULT: {component1.Operation()}");
86170
}
87171
}
88-
89-
class Program
172+
173+
class Program
90174
{
91175
static void Main(string[] args)
92176
{
93177
Client client = new Client();
94178

95-
Component leaf = new Leaf();
179+
// EN: This way the client code can support the simple leaf
180+
// components...
181+
//
182+
// RU: Таким образом, клиентский код может поддерживать простые
183+
// компоненты-листья...
184+
Leaf leaf = new Leaf();
96185
Console.WriteLine("Client: I get a simple component:");
97186
client.ClientCode(leaf);
98-
Console.WriteLine("\n");
99187

188+
// EN: ...as well as the complex composites.
189+
//
190+
// RU: ...а также сложные контейнеры.
100191
Composite tree = new Composite();
101192
Composite branch1 = new Composite();
102193
branch1.Add(new Leaf());
@@ -105,33 +196,11 @@ static void Main(string[] args)
105196
branch2.Add(new Leaf());
106197
tree.Add(branch1);
107198
tree.Add(branch2);
108-
Console.WriteLine("Client: Now I get a composite tree:");
199+
Console.WriteLine("Client: Now I've got a composite tree:");
109200
client.ClientCode(tree);
110-
Console.WriteLine("\n");
111201

112-
Console.Write("Client: I can merge two components without checking their classes:\n");
202+
Console.Write("Client: I don't need to check the components classes even when managing the tree:\n");
113203
client.ClientCode2(tree, leaf);
114204
}
115205
}
116-
117-
class Client
118-
{
119-
public void ClientCode(Component leaf)
120-
{
121-
Console.Write("RESULT: ");
122-
leaf.Operation();
123-
}
124-
125-
public void ClientCode2(Component component1, Component component2)
126-
{
127-
if (component1.IsComposite())
128-
{
129-
component1.Add(component2);
130-
}
131-
Console.Write("RESULT: ");
132-
component1.Operation();
133-
134-
Console.WriteLine();
135-
}
136-
}
137206
}

0 commit comments

Comments
 (0)