Skip to content

Commit 784e4ef

Browse files
authored
Merge pull request #17 from urboob21/dev_branch
id 1763622392
2 parents fdd86b2 + cb514f6 commit 784e4ef

File tree

3 files changed

+244
-0
lines changed

3 files changed

+244
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ set(APP_SOURCES
100100
"src/patterns/structural/Decorator.cpp"
101101
"src/patterns/behavioral/ChainOfCommand.cpp"
102102
"src/patterns/behavioral/Command.cpp"
103+
"src/patterns/behavioral/Iterator.cpp"
103104
)
104105

105106
# Test files

docs/uml/patterns_behavioral_iterator.drawio.svg

Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
// Iterator is a behavioral design pattern that lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.).
2+
// Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
3+
// Appicability:
4+
// (*) when your collection has a complex data structure under the hood, but you want to hide its complexity from clients (either for convenience or security reasons).
5+
// (**) reduce duplication of the traversal code across your app.
6+
// (***) when you want your code to be able to traverse different data structures or when types of these structures are unknown beforehand.
7+
8+
// UML: docs/uml/patterns_behavioral_iterator.drawio.svg
9+
10+
#include <iostream>
11+
#include <string>
12+
#include <vector>
13+
#include <list>
14+
#include <iterator>
15+
16+
namespace
17+
{
18+
namespace Iterator
19+
{
20+
class DataModel
21+
{
22+
private:
23+
int m_value;
24+
25+
public:
26+
explicit DataModel(int value) : m_value{value} {}
27+
28+
void setValue(int v)
29+
{
30+
m_value = v;
31+
}
32+
33+
int getValue() const { return m_value; }
34+
};
35+
36+
/**
37+
* Iterator interface: declares the operations required for traversing a collection: fetching the next element, retrieving the current position, restarting iteration, etc.
38+
*/
39+
template <typename T>
40+
class IIterator
41+
{
42+
public:
43+
virtual bool hasNext() const = 0;
44+
virtual const T *next() = 0;
45+
virtual ~IIterator() = default;
46+
};
47+
48+
/**
49+
* Aggregate interface: declares one or multiple methods for getting iterators compatible with the collection.
50+
* Note that the return type of the methods must be declared as the iterator interface so that the concrete collections can return various kinds of iterators.
51+
*/
52+
template <typename T>
53+
class IAggregate
54+
{
55+
public:
56+
virtual IIterator<T> *createIterator() = 0;
57+
virtual ~IAggregate() = default;
58+
};
59+
60+
/**
61+
* Concrete Iterator: implement specific algorithms for traversing a collection.
62+
* The iterator object should track the traversal progress on its own. This allows several iterators to traverse the same collection independently of each other.
63+
*/
64+
template <typename T>
65+
class VectorConcreteIterator : public IIterator<T>
66+
{
67+
private:
68+
const std::vector<T> &m_data;
69+
size_t m_currentIndex{0};
70+
71+
public:
72+
explicit VectorConcreteIterator(const std::vector<T> &data) : m_data{data} {}
73+
74+
bool hasNext() const override
75+
{
76+
return m_currentIndex < m_data.size();
77+
}
78+
79+
const T *next() override
80+
{
81+
if (hasNext())
82+
{
83+
return (T *)&m_data[m_currentIndex++];
84+
}
85+
else
86+
{
87+
return nullptr;
88+
}
89+
}
90+
};
91+
92+
template <typename T>
93+
class ListConcreteIterator : public IIterator<T>
94+
{
95+
private:
96+
const std::list<T> &m_data;
97+
typename std::list<T>::const_iterator m_it;
98+
99+
public:
100+
explicit ListConcreteIterator(const std::list<T> &data)
101+
: m_data(data), m_it(m_data.begin()) {}
102+
103+
bool hasNext() const override
104+
{
105+
return m_it != m_data.end();
106+
}
107+
108+
const T *next() override
109+
{
110+
if (!hasNext())
111+
return nullptr;
112+
const T *ptr = &(*m_it);
113+
++m_it;
114+
return ptr;
115+
}
116+
};
117+
118+
/**
119+
* Concrete Aggregate: return new instances of a particular concrete iterator class each time the client requests one.
120+
*/
121+
template <typename T>
122+
class ListConreteAggregate : public IAggregate<T>
123+
{
124+
private:
125+
std::list<T> m_data;
126+
127+
public:
128+
void add(const T &i)
129+
{
130+
m_data.push_back(i);
131+
}
132+
133+
IIterator<T> *createIterator() override
134+
{
135+
return new ListConcreteIterator<T>(m_data);
136+
}
137+
};
138+
139+
template <typename T>
140+
class VectorConcreteAggregate : public IAggregate<T>
141+
{
142+
private:
143+
std::vector<T> m_data;
144+
145+
public:
146+
void add(const T &i)
147+
{
148+
m_data.push_back(i);
149+
}
150+
151+
IIterator<T> *createIterator() override
152+
{
153+
return new VectorConcreteIterator<T>(m_data);
154+
}
155+
};
156+
157+
/**
158+
* The Client works with both collections and iterators via their interfaces.
159+
* This way the client isn’t coupled to concrete classes, allowing you to use various collections and iterators with the same client code.
160+
*/
161+
namespace Client
162+
{
163+
164+
void clientCode(IAggregate<int> *collection)
165+
{
166+
IIterator<int> *iterator = collection->createIterator();
167+
168+
if (iterator != nullptr)
169+
{
170+
while (iterator->hasNext())
171+
{
172+
std::cout << "int: " << *(iterator->next()) << "\n";
173+
}
174+
}
175+
176+
delete iterator;
177+
}
178+
179+
void clientCode(IAggregate<DataModel> *collection)
180+
{
181+
IIterator<DataModel> *iterator = collection->createIterator();
182+
183+
if (iterator != nullptr)
184+
{
185+
while (iterator->hasNext())
186+
{
187+
std::cout << "data: " << iterator->next()->getValue() << "\n";
188+
}
189+
}
190+
delete iterator;
191+
}
192+
}
193+
194+
void run()
195+
{
196+
std::cout << "\nVectorConcreteAggregate\n";
197+
VectorConcreteAggregate<int> intCollection;
198+
for (int i = 0; i < 10; ++i)
199+
{
200+
intCollection.add(i);
201+
}
202+
Client::clientCode(&intCollection);
203+
std::cout << "\n";
204+
VectorConcreteAggregate<DataModel> dataCollection;
205+
for (int i = 0; i < 10; ++i)
206+
{
207+
dataCollection.add(DataModel(i * 10));
208+
}
209+
Client::clientCode(&dataCollection);
210+
211+
std::cout << "\nListConreteAggregate\n";
212+
ListConreteAggregate<int> intCollection2;
213+
for (int i = 0; i < 10; ++i)
214+
{
215+
intCollection2.add(i);
216+
}
217+
218+
Client::clientCode(&intCollection2);
219+
std::cout << "\n";
220+
ListConreteAggregate<DataModel> dataCollection2;
221+
for (int i = 0; i < 10; ++i)
222+
{
223+
dataCollection2.add(DataModel(i * 10));
224+
}
225+
Client::clientCode(&dataCollection2);
226+
}
227+
}
228+
}
229+
230+
struct IteratorAutoRunner
231+
{
232+
IteratorAutoRunner()
233+
{
234+
std::cout << "\n--- Iterator Pattern Example ---\n";
235+
Iterator::run();
236+
}
237+
};
238+
239+
static IteratorAutoRunner instance;

0 commit comments

Comments
 (0)