Skip to content

Commit e6681ce

Browse files
Eder DuranEder Duran
authored andcommitted
Visitor design pattern
1 parent 9aafd25 commit e6681ce

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

src/Visitor/Conceptual/Output.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
The client code works with all visitors via the base Visitor interface:
2+
A + ConcreteVisitor1
3+
B + ConcreteVisitor1
4+
5+
It allows the same client code to work with different types of visitors:
6+
A + ConcreteVisitor2
7+
B + ConcreteVisitor2
8+

src/Visitor/Conceptual/main.cc

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
#include <iostream>
2+
#include <string>
3+
#include <array>
4+
5+
/**
6+
* EN: Visitor Design Pattern
7+
*
8+
* Intent: Lets you separate algorithms from the objects on which they operate.
9+
*
10+
* RU: Паттерн Посетитель
11+
*
12+
* Назначение: Позволяет создавать новые операции, не меняя классы объектов, над
13+
* которыми эти операции могут выполняться.
14+
*/
15+
16+
/**
17+
* EN: The Visitor Interface declares a set of visiting methods that correspond
18+
* to component classes. The signature of a visiting method allows the visitor
19+
* to identify the exact class of the component that it's dealing with.
20+
*
21+
* RU: Интерфейс Посетителя объявляет набор методов посещения, соответствующих
22+
* классам компонентов. Сигнатура метода посещения позволяет посетителю
23+
* определить конкретный класс компонента, с которым он имеет дело.
24+
*/
25+
class ConcreteComponentA;
26+
class ConcreteComponentB;
27+
28+
class Visitor
29+
{
30+
public:
31+
virtual void VisitConcreteComponentA(const ConcreteComponentA *element) const = 0;
32+
virtual void VisitConcreteComponentB(const ConcreteComponentB *element) const = 0;
33+
};
34+
35+
/**
36+
* EN: The Component interface declares an `accept` method that should take the
37+
* base visitor interface as an argument.
38+
*
39+
* RU: Интерфейс Компонента объявляет метод accept, который в качестве аргумента
40+
* может получать любой объект, реализующий интерфейс посетителя.
41+
*/
42+
43+
class Component
44+
{
45+
public:
46+
virtual ~Component() {}
47+
virtual void Accept(Visitor *visitor) const = 0;
48+
};
49+
50+
/**
51+
* EN: Each Concrete Component must implement the `Accept` method in such a way
52+
* that it calls the visitor's method corresponding to the component's class.
53+
*
54+
* RU: Каждый Конкретный Компонент должен реализовать метод accept таким
55+
* образом, чтобы он вызывал метод посетителя, соответствующий классу
56+
* компонента.
57+
*/
58+
class ConcreteComponentA : public Component
59+
{
60+
/**
61+
* EN: Note that we're calling `visitConcreteComponentA`, which matches the
62+
* current class name. This way we let the visitor know the class of the
63+
* component it works with.
64+
*
65+
* RU: Обратите внимание, мы вызываем visitConcreteComponentA, что
66+
* соответствует названию текущего класса. Таким образом мы позволяем
67+
* посетителю узнать, с каким классом компонента он работает.
68+
*/
69+
public:
70+
void Accept(Visitor *visitor) const override
71+
{
72+
visitor->VisitConcreteComponentA(this);
73+
}
74+
/**
75+
* EN: Concrete Components may have special methods that don't exist in
76+
* their base class or interface. The Visitor is still able to use these
77+
* methods since it's aware of the component's concrete class.
78+
*
79+
* RU: Конкретные Компоненты могут иметь особые методы, не объявленные в их
80+
* базовом классе или интерфейсе. Посетитель всё же может использовать эти
81+
* методы, поскольку он знает о конкретном классе компонента.
82+
*/
83+
std::string ExclusiveMethodOfConcreteComponentA() const
84+
{
85+
return "A";
86+
}
87+
};
88+
89+
class ConcreteComponentB : public Component
90+
{
91+
/**
92+
* EN: Same here: visitConcreteComponentB => ConcreteComponentB
93+
*
94+
* RU: То же самое здесь: visitConcreteComponentB => ConcreteComponentB
95+
*/
96+
public:
97+
void Accept(Visitor *visitor) const override
98+
{
99+
visitor->VisitConcreteComponentB(this);
100+
}
101+
std::string SpecialMethodOfConcreteComponentB() const
102+
{
103+
return "B";
104+
}
105+
};
106+
107+
/**
108+
* EN: Concrete Visitors implement several versions of the same algorithm, which
109+
* can work with all concrete component classes.
110+
*
111+
* You can experience the biggest benefit of the Visitor pattern when using it
112+
* with a complex object structure, such as a Composite tree. In this case, it
113+
* might be helpful to store some intermediate state of the algorithm while
114+
* executing visitor's methods over various objects of the structure.
115+
*
116+
* RU: Конкретные Посетители реализуют несколько версий одного и того же
117+
* алгоритма, которые могут работать со всеми классами конкретных компонентов.
118+
*
119+
* Максимальную выгоду от паттерна Посетитель вы почувствуете, используя его со
120+
* сложной структурой объектов, такой как дерево Компоновщика. В этом случае
121+
* было бы полезно хранить некоторое промежуточное состояние алгоритма при
122+
* выполнении методов посетителя над различными объектами структуры.
123+
*/
124+
class ConcreteVisitor1 : public Visitor
125+
{
126+
public:
127+
void VisitConcreteComponentA(const ConcreteComponentA *element) const override
128+
{
129+
std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor1\n";
130+
}
131+
132+
void VisitConcreteComponentB(const ConcreteComponentB *element) const override
133+
{
134+
std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor1\n";
135+
}
136+
};
137+
138+
class ConcreteVisitor2 : public Visitor
139+
{
140+
public:
141+
void VisitConcreteComponentA(const ConcreteComponentA *element) const override
142+
{
143+
std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor2\n";
144+
}
145+
void VisitConcreteComponentB(const ConcreteComponentB *element) const override
146+
{
147+
std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor2\n";
148+
}
149+
};
150+
/**
151+
* EN: The client code can run visitor operations over any set of elements
152+
* without figuring out their concrete classes. The accept operation directs a
153+
* call to the appropriate operation in the visitor object.
154+
*
155+
* RU: Клиентский код может выполнять операции посетителя над любым набором
156+
* элементов, не выясняя их конкретных классов. Операция принятия направляет
157+
* вызов к соответствующей операции в объекте посетителя.
158+
*/
159+
void ClientCode(std::array<const Component *, 2> components, Visitor *visitor)
160+
{
161+
// ...
162+
for (const Component *comp : components)
163+
{
164+
comp->Accept(visitor);
165+
}
166+
// ...
167+
}
168+
169+
int main()
170+
{
171+
std::array<const Component *, 2> components = {new ConcreteComponentA, new ConcreteComponentB};
172+
std::cout << "The client code works with all visitors via the base Visitor interface:\n";
173+
ConcreteVisitor1 *visitor1 = new ConcreteVisitor1;
174+
ClientCode(components, visitor1);
175+
std::cout << "\n";
176+
std::cout << "It allows the same client code to work with different types of visitors:\n";
177+
ConcreteVisitor2 *visitor2 = new ConcreteVisitor2;
178+
ClientCode(components, visitor2);
179+
180+
for (const Component *comp : components)
181+
{
182+
delete comp;
183+
}
184+
delete visitor1;
185+
delete visitor2;
186+
187+
return 0;
188+
}

0 commit comments

Comments
 (0)