GoFデザインパターン ~Iteratorパターン~
こちらを読みながら進める。
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2004/06/19
- メディア: 大型本
- 購入: 51人 クリック: 762回
- この商品を含むブログ (397件) を見る
Iteratorパターンとは
コレクションに対する繰り返し処理で使われるパターン。コレクションオブジェクトとイテレータを分離し、イテレータをinterfaceで抽象化することで、利用側がコレクションのデータ構造に依存することなくiterate処理を行えるようになるというもの。
登場人物の関係をシンプルに書くとこんな感じ。
集約とイテレータを分離するために集約の実装には Iterator()
が要求され、イテレーションにおける具体的なコレクション操作はIteratorインターフェースを実装したImplementIterator
に委譲される。ので、利用側は集約への依存ではなくIteratorインターフェースへの依存によってiterate処理を行うことができる。
実装
増補改訂版Java言語で学ぶデザインパターン入門で使われてる本棚の例をGoで実装してみる。
要件は、本(Entity)を格納する本棚(Aggregate)を作り、main処理で本棚に入っている本の名前を順番に表示するというもの。
ディレクトリ構成は以下
├── bookshelf │ ├── Aggregate.go │ ├── Book.go │ ├── Bookshelf.go │ ├── Bookshelfiterator.go │ ├── Iterator.go │ └── Product.go └── main.go
Aggregate
Aggregateインターフェース。
package bookshelf type Aggregate interface { Iterator() *Iterator }
ImplementAggregate。簡単な配列操作とIterator()の実装
package bookshelf type bookshelf struct { books []Product last int } func NewBookShelf(maxsize int) *bookshelf { return &bookshelf{books: make([]Product, maxsize), last: 0} } func (bs *bookshelf) GetByIndex(index int) Product { return bs.books[index] } func (bs *bookshelf) AppendBook(b Product) { bs.books[bs.last] = b bs.last++ } func (bs *bookshelf) GetLength() int { return bs.last } func (bs *bookshelf) Iterator() Iterator { return NewBookshelfIterator(bs) }
Iterator
Iteratorインターフェース。このあたりは要求に合わせて変えていけば良さそう
package bookshelf type Iterator interface { HasNext() bool Next() Product }
ImplementIteratorの実装。
package bookshelf type bookshelfIterator struct { bookshelf Aggregate index int } func NewBookshelfIterator(bookshelf Aggregate) Iterator { return &bookshelfIterator{bookshelf: bookshelf, index: 0} } func (it *bookshelfIterator) HasNext() bool { return it.index < it.bookshelf.GetLength() } func (it *bookshelfIterator) Next() Product { book := it.bookshelf.GetByIndex(it.index) it.index++ return book }
Entity
Entityを表すProductインターフェース。ここまで厳密な型を用意しなくていいかも
package bookshelf type Product interface { GetName() string }
package bookshelf type book struct { name string } func NewBook(name string) *book { return &book{name} } func (b *book) GetName() string { return b.name }
main
main処理
package main import ( "fmt" "github.com/saekis/go-design-pattern/1_iterator/bookshelf" ) func main() { bs := bookshelf.NewBookShelf(3) bs.AppendBook(bookshelf.NewBook("リーダブルコード")) bs.AppendBook(bookshelf.NewBook("達人プログラマ")) bs.AppendBook(bookshelf.NewBook("Team Geek")) it := bs.Iterator() for it.HasNext() { book := it.Next() fmt.Println(book.GetName()) } }
実行結果
$ go run main.go リーダブルコード 達人プログラマ Team Geek
サンプル実装したクラス図