Iterator

  • 集約オブジェクト内の各オブジェクトへのアクセス手段を統一する
  • 普通はSTLコンテナのiteratorを使う
  • 集約オブジェクトの変更があっても、iteratorオブジェクトを介するので取得側コードを変更する必要はない


Structural example
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4.  
  5. // prototype
  6. template <class T> class Iterator;
  7. template <class T> class ConcreteIterator;
  8.  
  9. // The 'Aggregate' abstract class
  10. template <class T>
  11. class Aggregate {
  12. public:
  13. virtual ~Aggregate() { }
  14. virtual Iterator<T>* CreateIterator() = 0;
  15. };
  16.  
  17. // The 'ConcreteAggregate' class
  18. template <class T>
  19. class ConcreteAggregate : public Aggregate<T> {
  20. public:
  21. // constructor
  22. ConcreteAggregate(int size) {
  23. _items = new T[size];
  24. _max_size = size;
  25. _count = 0;
  26. }
  27. // destructor
  28. virtual ~ConcreteAggregate() {
  29. delete [] _items;
  30. }
  31. // CreateIterator
  32. Iterator<T>* CreateIterator() {
  33. return new ConcreteIterator<T>(this);
  34. }
  35. // Count
  36. int Count() {
  37. return _count;
  38. }
  39. // Get
  40. T* Get(int index) {
  41. return &_items[index];
  42. }
  43. // Set
  44. void Set(const T& value) {
  45. if (_count < _max_size) {
  46. _items[_count++] = value;
  47. }
  48. }
  49. private:
  50. T *_items;
  51. int _max_size;
  52. int _count;
  53. };
  54.  
  55. // The 'Iterator' abstract class
  56. template <class T>
  57. class Iterator {
  58. public:
  59. virtual ~Iterator() { }
  60. virtual T* First() = 0;
  61. virtual T* Next() = 0;
  62. virtual T* CurrentItem() = 0;
  63. virtual bool IsDone() = 0;
  64. };
  65.  
  66. // The 'ConcreteIterator' class
  67. template <class T>
  68. class ConcreteIterator : public Iterator<T> {
  69. public:
  70. // constructor
  71. ConcreteIterator(ConcreteAggregate<T> *aggregate) {
  72. _aggregate = aggregate;
  73. _current = 0;
  74. }
  75. // First
  76. T* First() {
  77. return _aggregate->Get(0);
  78. }
  79. // Next
  80. T* Next() {
  81. T *ret = NULL;
  82. if (_current < _aggregate->Count() - 1) {
  83. ret = _aggregate->Get(++_current);
  84. }
  85. return ret;
  86. }
  87. // CurrentItem
  88. T* CurrentItem() {
  89. return _aggregate->Get(_current);
  90. }
  91. // IsDone
  92. bool IsDone() {
  93. return (_current >= _aggregate->Count());
  94. }
  95. private:
  96. ConcreteAggregate<T> *_aggregate;
  97. int _current;
  98. };
  99.  
  100. // client
  101. int main() {
  102. ConcreteAggregate<string> *a = new ConcreteAggregate<string>(4);
  103. a->Set("Item A");
  104. a->Set("Item B");
  105. a->Set("Item C");
  106. a->Set("Item D");
  107.  
  108. ConcreteIterator<string> *i = new ConcreteIterator<string>(a);
  109. // Iterator<string> *i = a->CreateIterator(); // 上と同じ
  110.  
  111. string *item = i->First();
  112. while (item != NULL) {
  113. cout << *item << endl;
  114. item = i->Next();
  115. }
  116.  
  117. delete a;
  118. delete i;
  119. return 0;
  120. }
  121.  

Real World example
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4.  
  5. // prototype
  6. template <class T> class IAbstractIterator;
  7. template <class T> class Iterator;
  8.  
  9. // A collection item
  10. class Item {
  11. public:
  12. // constructor
  13. Item(const string &name) {
  14. _name = name;
  15. }
  16. // Get
  17. string GetName() {
  18. return _name;
  19. }
  20. private:
  21. string _name;
  22. };
  23.  
  24. // The 'Aggregate' interface class
  25. template <class T>
  26. class IAbstractCollection {
  27. public:
  28. virtual ~IAbstractCollection() { };
  29. virtual Iterator<T>* CreateIterator() = 0;
  30. };
  31.  
  32. // The 'ConcreteAggregate' class
  33. template <class T>
  34. class Collection : public IAbstractCollection<T> {
  35. public:
  36. // constructor
  37. Collection(int size) {
  38. _items = new T[size];
  39. _max_size = size;
  40. _count = 0;
  41. }
  42. // destructor
  43. virtual ~Collection() {
  44. delete [] _items;
  45. }
  46. // CreateIterator
  47. Iterator<T>* CreateIterator() {
  48. return new Iterator<T>(this);
  49. }
  50. // Count
  51. int Count() {
  52. return _count;
  53. }
  54. // Get
  55. T* Get(int index) {
  56. return &_items[index];
  57. }
  58. // Set
  59. void Set(const T& value) {
  60. if (_count < _max_size) {
  61. _items[_count++] = value;
  62. }
  63. }
  64. private:
  65. T *_items;
  66. int _max_size;
  67. int _count;
  68. };
  69.  
  70. // The 'Iterator' interface class
  71. template <class T>
  72. class IAbstractIterator {
  73. public:
  74. virtual ~IAbstractIterator() { };
  75. virtual T* First() = 0;
  76. virtual T* Next() = 0;
  77. virtual T* CurrentItem() = 0;
  78. virtual bool IsDone() = 0;
  79. };
  80.  
  81. // The 'ConcreteIterator' class
  82. template <class T>
  83. class Iterator : public IAbstractIterator<T> {
  84. public:
  85. // constructor
  86. Iterator(Collection<T> *collection) {
  87. _collection = collection;
  88. _current = 0;
  89. _step = 1;
  90. }
  91. // First
  92. T* First() {
  93. _current = 0;
  94. return _collection->Get(0);
  95. }
  96. // Next
  97. T* Next() {
  98. _current += _step;
  99. if (!IsDone()) {
  100. return _collection->Get(_current);
  101. } else {
  102. return NULL;
  103. }
  104. }
  105. // GetStep
  106. int GetStep() {
  107. return _step;
  108. }
  109. // SetStep
  110. void SetStep(int step) {
  111. _step = step;
  112. }
  113. // CurrentItem
  114. T* CurrentItem() {
  115. return _collection->Get(_current);
  116. }
  117. // IsDone
  118. bool IsDone() {
  119. return (_current >= _collection->Count());
  120. }
  121. private:
  122. Collection<T> *_collection;
  123. int _current;
  124. int _step;
  125. };
  126.  
  127. // client
  128. int main() {
  129. Collection<Item*> *collection = new Collection<Item*>(9);
  130. collection->Set(new Item("Item 0"));
  131. collection->Set(new Item("Item 1"));
  132. collection->Set(new Item("Item 2"));
  133. collection->Set(new Item("Item 3"));
  134. collection->Set(new Item("Item 4"));
  135. collection->Set(new Item("Item 5"));
  136. collection->Set(new Item("Item 6"));
  137. collection->Set(new Item("Item 7"));
  138. collection->Set(new Item("Item 8"));
  139.  
  140. // Create iterator
  141. Iterator<Item*> *iterator = new Iterator<Item*>(collection);
  142.  
  143. // Skip every other item
  144. iterator->SetStep(2);
  145.  
  146. for (Item **item = iterator->First();
  147. !iterator->IsDone();
  148. item = iterator->Next())
  149. {
  150. cout << (*item)->GetName() << endl;
  151. }
  152.  
  153. delete collection;
  154. delete iterator;
  155. return 0;
  156. }
  157.  


抽象クラスなし
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4.  
  5. // prototype
  6. class BookIterator;
  7.  
  8. // 集約されるオブジェクトクラス
  9. class Book {
  10. public:
  11. Book(const string &name) {
  12. m_name = name;
  13. }
  14. string GetName() {
  15. return m_name;
  16. }
  17. private:
  18. string m_name;
  19. };
  20.  
  21. // Aggregate: 集約クラス
  22. class BookAggregate {
  23. public:
  24. // constructor
  25. BookAggregate() {
  26. m_plist = NULL;
  27. m_list_size = 0;
  28. }
  29. // destructor
  30. ~BookAggregate() {
  31. BookList *p, *next;
  32. for (p = m_plist; p != NULL; p = next) {
  33. delete p->book;
  34. next = p->next;
  35. delete p;
  36. }
  37. }
  38. // Add
  39. void Add(Book *book) {
  40. // リスト最後尾へ追加
  41. BookList *p, *p_bfr = NULL;
  42. int size = 1;
  43. for (p = m_plist; p != NULL; p_bfr = p, p = p->next, ++size);
  44. p = new BookList;
  45. p->book = book;
  46. if (m_plist == NULL) {
  47. // 初回は先頭を確保
  48. m_plist = p;
  49. }
  50. if (p_bfr != NULL) {
  51. // 初回以外は前の要素へ今作った要素へのポインタを確保
  52. p_bfr->next = p;
  53. }
  54. // リストサイズ更新
  55. m_list_size = size;
  56. }
  57. // Get
  58. Book* Get(int index) {
  59. BookList *p, *p_bfr = NULL;
  60. int i;
  61. if (index < 0 || index >= m_list_size) {
  62. return NULL;
  63. }
  64. for (i = 0, p = m_plist; p != NULL; ++i, p = p->next) {
  65. if (i == index) {
  66. return p->book;
  67. }
  68. }
  69. return NULL;
  70. }
  71. // Size
  72. int Size() {
  73. return m_list_size;
  74. }
  75. // CreateIterator
  76. BookIterator* CreateIterator();
  77. private:
  78. // リスト構造体定義
  79. struct BookList {
  80. Book *book;
  81. BookList *next;
  82. BookList() {
  83. book = NULL;
  84. next = NULL;
  85. }
  86. }; // struct BookList
  87. BookList *m_plist; // list
  88. int m_list_size; // size
  89. };
  90.  
  91. // Iterator: 反復子クラス
  92. class BookIterator {
  93. public:
  94. // constructor
  95. BookIterator(BookAggregate *aggregate) {
  96. m_aggregate = aggregate;
  97. m_current = 0;
  98. }
  99. // First
  100. void First() {
  101. m_current = 0;
  102. }
  103. // Next
  104. void Next() {
  105. ++m_current;
  106. }
  107. // IsDone
  108. bool IsDone() {
  109. return (m_current >= m_aggregate->Size());
  110. }
  111. // CurrentItem
  112. Book* CurrentItem() {
  113. return m_aggregate->Get(m_current);
  114. }
  115. // Destroy
  116. void Destroy() {
  117. delete this;
  118. }
  119. private:
  120. BookAggregate *m_aggregate;
  121. int m_current;
  122. };
  123.  
  124. // BookAggregate::CreateIterator
  125. BookIterator* BookAggregate::CreateIterator() {
  126. return new BookIterator(this);
  127. }
  128.  
  129. // client
  130. int main() {
  131. BookAggregate *list = new BookAggregate();
  132. // 登録
  133. list->Add(new Book("book 1"));
  134. list->Add(new Book("book 2"));
  135. list->Add(new Book("book 3"));
  136.  
  137. // iterator で参照
  138. BookIterator *it = list->CreateIterator();
  139. for (it->First(); !it->IsDone(); it->Next()) {
  140. cout << it->CurrentItem()->GetName() << endl;
  141. }
  142.  
  143. // 終了処理
  144. it->Destroy();
  145. delete list;
  146. return 0;
  147. }
  148.  

出力
book 1
book 2
book 3


  1. #include <iostream>
  2. #include <string>
  3.  
  4. using namespace std;
  5.  
  6. // 生徒クラス
  7. class Student {
  8. public:
  9. Student(const string& name, int sex) {
  10. m_name = name;
  11. m_sex = sex;
  12. }
  13. string getName() {
  14. return m_name;
  15. }
  16. int getSex() {
  17. return m_sex;
  18. }
  19. private:
  20. string m_name;
  21. int m_sex;
  22. };
  23.  
  24.  
  25. // 生徒リスト
  26. class StudentList {
  27. public:
  28. StudentList(int count) {
  29. m_students = new Student*[count];
  30. m_last = 0;
  31. }
  32. ~StudentList() {
  33. for (int i=0; i<getLastNum(); ++i) {
  34. delete m_students[i];
  35. }
  36. delete [] m_students;
  37. }
  38. void add(Student* student) {
  39. m_students[m_last++] = student;
  40. }
  41. Student* getStudentAt(int index) {
  42. return m_students[index];
  43. }
  44. int getLastNum() {
  45. return m_last;
  46. }
  47. protected:
  48. Student **m_students;
  49. private:
  50. int m_last;
  51. };
  52.  
  53.  
  54. // 新しい生徒リスト
  55. #include <vector>
  56. class NewStudentList {
  57. public:
  58. virtual ~NewStudentList() {
  59. for (int i=0; i<m_students.size(); ++i) {
  60. delete m_students.at(i);
  61. }
  62. }
  63. void add(Student* student) {
  64. m_students.push_back(student);
  65. }
  66. Student* getStudentAt(int index) {
  67. return m_students.at(index);
  68. }
  69. int getListSize() { // インターフェイスが変わった
  70. return m_students.size();
  71. }
  72. protected:
  73. vector<Student*> m_students;
  74. };
  75.  
  76.  
  77. // イテレータ
  78. class Iterator {
  79. public:
  80. virtual bool hasNext() = 0;
  81. virtual void* next() = 0;
  82. };
  83.  
  84.  
  85. // アグリゲート
  86. class Aggregate {
  87. public:
  88. virtual Iterator* iterator() = 0;
  89. };
  90.  
  91.  
  92. // プロトタイプ(前方)宣言
  93. // 継承していることを前方宣言で表すことはできない
  94. //class MyStudentListIterator;
  95.  
  96.  
  97. #if 0
  98. // イテレータするための生徒リスト
  99. class MyStudentList
  100. : public StudentList, public Aggregate
  101. {
  102. public:
  103. MyStudentList(int count) : StudentList(count) { }
  104. Iterator* iterator(); // MyStudentListIterator を使うので、宣言後に。
  105. };
  106. #else
  107. // イテレータするための新しい生徒リスト
  108. class MyStudentList
  109. : public NewStudentList, public Aggregate
  110. {
  111. public:
  112. Iterator* iterator();
  113. };
  114. #endif
  115.  
  116.  
  117. // イテレータの実装
  118. class MyStudentListIterator : public Iterator {
  119. public:
  120. MyStudentListIterator(MyStudentList* list) {
  121. m_StudentList = list;
  122. m_index = 0;
  123. }
  124. bool hasNext() {
  125. #if 0
  126. if (m_StudentList->getLastNum() > m_index) {
  127. return true;
  128. } else {
  129. return false;
  130. }
  131. #else
  132. // 新しい生徒リストはインターフェイスが変わった
  133. if (m_StudentList->getListSize() > m_index) {
  134. return true;
  135. } else {
  136. return false;
  137. }
  138. #endif
  139. }
  140. void* next() {
  141. return (void*)m_StudentList->getStudentAt(m_index++);
  142. }
  143. private:
  144. MyStudentList *m_StudentList;
  145. int m_index;
  146. };
  147.  
  148.  
  149. // MyStudentListIterator 宣言後に書く
  150. Iterator* MyStudentList::iterator()
  151. {
  152. // ポインタ/参照ではないので、前方宣言ではコンパイルエラー
  153. return new MyStudentListIterator(this);
  154. }
  155.  
  156.  
  157. int main(int argc, char **argv) {
  158. // リスト登録
  159. #if 0
  160. MyStudentList *list = new MyStudentList(2);
  161. #else
  162. // 新しい生徒リストに変更
  163. MyStudentList *list = new MyStudentList;
  164. #endif
  165. list->add(new Student("たろう", 1));
  166. list->add(new Student("はなこ", 2));
  167.  
  168. // イテレータを使って表示
  169. Iterator* itr = list->iterator();
  170. while (itr->hasNext()) {
  171. cout << ((Student*)itr->next())->getName() << endl;
  172. }
  173. delete list;
  174.  
  175. return 0;
  176. }
  177.  



参考サイト

デザインパターンを“喩え話”で分かり易く理解する
http://www.netlaputa.ne.jp/~hijk/study/oo/designpattern.html



デザインパターンの骸骨たち
http://www002.upp.so-net.ne.jp/ys_oota/mdp/

デザインパターンの使い方:Iterator
http://japan.internet.com/developer/20090529/26.html
最終更新:2012年02月22日 00:05