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