集合の各要素に順次アクセスする仕組みを作るパターン。
クラスに集合の役割をもたせ、イテレータを提供させることで、順次アクセス可能にする。
集合の要素を直接参照するのではなく、イテレータを介してアクセスすることで、集合の具体的な実装方法(配列とかListとかVectorとか)に依らず要素を数え上げられるようになることがメリット。
イテレータの振る舞いも好きに実装できるので、例えばある条件に適合する要素だけイテレーションする(部分集合のイテレーション)、みたいなことができると思う。
ソースコード
C++11で記述。
本棚クラスを本クラスの集合として扱う。
本棚クラスにイテレータを提供させ、イテレータを介して本クラスのメンバ関数にアクセスしている。
#include <iostream> #include <string> #include <vector> #include <memory> class Iterator; class Book; // クラスをイテレータをもつ集合として扱うためのインタフェース class Aggregate { public: virtual std::unique_ptr<Iterator> GetIterator() = 0; }; // イテレータとしての役割を与えるインタフェース class Iterator { public: virtual ~Iterator(){}; virtual bool HasNext() = 0; virtual void* Next() = 0; }; // 本を表すクラス (集合の要素) class Book { public: void SetName(const std::string name) { this->name_ = name; } std::string GetName() { return this->name_; } private: std::string name_; }; // 本棚を表すクラス (集合) class BookShelf : public Aggregate { public: BookShelf(const int maxSize) : bookCount_(0) { books_.resize(maxSize); } Book* GetBookAt(const int index) { return &(this->books_[index]); } void AppendBook(const Book book) { this->books_[bookCount_] = book; bookCount_++; } int GetLength() { return bookCount_; } std::unique_ptr<Iterator> GetIterator() override; private: std::vector<Book> books_; int bookCount_; }; // イテレータ class BookShelfIterator : public Iterator { public: BookShelfIterator(const BookShelf bookShelf) : bookShelf_(bookShelf), index_(0) {} bool HasNext() override { if(index_ < bookShelf_.GetLength()) { return true; } else { return false; } } void* Next() override { Book *pBook = bookShelf_.GetBookAt(index_); index_++; return pBook; } private: BookShelf bookShelf_; int index_; }; std::unique_ptr<Iterator> BookShelf::GetIterator() { return std::unique_ptr<BookShelfIterator>(new BookShelfIterator(*this)); } int main() { Book book1; Book book2; Book book3; Book book4; book1.SetName("Inherit the Stars"); book2.SetName("2001: A Space Odyssey"); book3.SetName("The Door into Summer"); book4.SetName("Do Androids Dream of Electric Sheep?"); BookShelf bookShelf(4); bookShelf.AppendBook(book1); bookShelf.AppendBook(book2); bookShelf.AppendBook(book3); bookShelf.AppendBook(book4); auto it = bookShelf.GetIterator(); while(it->HasNext()) { Book *book = reinterpret_cast<Book*>(it->Next()); std::cout << book->GetName() << std::endl; } }
参考
以下の書籍、Webページを参考にしました。