From 3db20e54762bf89e7d4d635e0ccd0a317b7564ce Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Thu, 20 Nov 2025 14:05:01 +0700 Subject: [PATCH 1/2] Add Iterator pattern --- CMakeLists.txt | 1 + .../patterns_behavioral_iterator.drawio.svg | 4 + src/patterns/behavioral/Iterator.cpp | 239 ++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 docs/uml/patterns_behavioral_iterator.drawio.svg create mode 100644 src/patterns/behavioral/Iterator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e974cb..eb4f7b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ set(APP_SOURCES "src/patterns/structural/Decorator.cpp" "src/patterns/behavioral/ChainOfCommand.cpp" "src/patterns/behavioral/Command.cpp" + "src/patterns/behavioral/Iterator.cpp" ) # Test files diff --git a/docs/uml/patterns_behavioral_iterator.drawio.svg b/docs/uml/patterns_behavioral_iterator.drawio.svg new file mode 100644 index 0000000..ffa0cf9 --- /dev/null +++ b/docs/uml/patterns_behavioral_iterator.drawio.svg @@ -0,0 +1,4 @@ + + + +
Client
+ clientCode(IAggregate<T> * collection): type

<<Interface>>
IAggregate


+ createIterator: IIterator*

<<Interface>>
IIterator


+ hasNext(): bool

+ next(): *T

VectorConcreteIterator
- m_container: const std::vector<T>* const
- size_t m_currentIndex{0};

+ hasNext(): bool

+ next(): *T

ListConcreteIterator
+ m_org_container:const std::vector<T>* const
- size_t m_currentIndex{0};

+ hasNext(): bool

+ next(): *T

VectorConcreteAggregate
- m_container: std::vector<T> 
+ add(T i): void
+ createIterator: IIterator*
ListConcreteAggregate
- m_container: std::list<T> 
+ add(T i): void
+ createIterator: IIterator*
Use
Use
<<create>>
<<create>>
<<create>>
1
1
Extends
Extends
Extends
Extends
createIterator:
{
return new VectorConcreteIterator<T>(m_data);
}
hasNext:
{
return m_currentIndex < m_container.size();
}

next:
{
  if (hasNext()) { 
return (T *)&m_data[m_currentIndex++]; 
  } else { 
return nullptr; 
  }
}
clientCode:
{
IIterator<T> *iterator = collection->createIterator();
if (iterator != nullptr) {
  while (iterator->hasNext()) 
{ 
const T* child = iterator->next(); 
} 
  }
delete iterator;
}
\ No newline at end of file diff --git a/src/patterns/behavioral/Iterator.cpp b/src/patterns/behavioral/Iterator.cpp new file mode 100644 index 0000000..498c232 --- /dev/null +++ b/src/patterns/behavioral/Iterator.cpp @@ -0,0 +1,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_command.drawio.svg + +#include +#include +#include +#include +#include + +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 + 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 + class IAggregate + { + public: + virtual IIterator *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 + class VectorConcreteIterator : public IIterator + { + private: + const std::vector &m_data; + size_t m_currentIndex{0}; + + public: + explicit VectorConcreteIterator(const std::vector &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 + class ListConcreteIterator : public IIterator + { + private: + const std::list &m_data; + typename std::list::const_iterator m_it; + + public: + explicit ListConcreteIterator(const std::list &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 + class ListConreteAggregate : public IAggregate + { + private: + std::list m_data; + + public: + void add(const T &i) + { + m_data.push_back(i); + } + + IIterator *createIterator() override + { + return new ListConcreteIterator(m_data); + } + }; + + template + class VectorConcreteAggregate : public IAggregate + { + private: + std::vector m_data; + + public: + void add(const T &i) + { + m_data.push_back(i); + } + + IIterator *createIterator() override + { + return new VectorConcreteIterator(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 *collection) + { + IIterator *iterator = collection->createIterator(); + + if (iterator != nullptr) + { + while (iterator->hasNext()) + { + std::cout << "int: " << *(iterator->next()) << "\n"; + } + } + + delete iterator; + } + + void clientCode(IAggregate *collection) + { + IIterator *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 intCollection; + for (int i = 0; i < 10; ++i) + { + intCollection.add(i); + } + Client::clientCode(&intCollection); + std::cout << "\n"; + VectorConcreteAggregate dataCollection; + for (int i = 0; i < 10; ++i) + { + dataCollection.add(DataModel(i * 10)); + } + Client::clientCode(&dataCollection); + + std::cout << "\nListConreteAggregate\n"; + ListConreteAggregate intCollection2; + for (int i = 0; i < 10; ++i) + { + intCollection2.add(i); + } + + Client::clientCode(&intCollection2); + std::cout << "\n"; + ListConreteAggregate 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; \ No newline at end of file From cb514f6b7a6a8e1ad3d2486b2c3eb22ff83a9460 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Thu, 20 Nov 2025 14:07:48 +0700 Subject: [PATCH 2/2] fix doc issue --- src/patterns/behavioral/Iterator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patterns/behavioral/Iterator.cpp b/src/patterns/behavioral/Iterator.cpp index 498c232..4ba2cd2 100644 --- a/src/patterns/behavioral/Iterator.cpp +++ b/src/patterns/behavioral/Iterator.cpp @@ -5,7 +5,7 @@ // (**) 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_command.drawio.svg +// UML: docs/uml/patterns_behavioral_iterator.drawio.svg #include #include