1. イテレーター パターンとは
イテレーター パターンとは、集合オブジェクトの要素を内部表現を公開せずに走査するための統一的な方法を提供する振る舞いのデザインパターンです。
2. イテレーター パターンの特徴と利点
イテレーター パターンの特徴と利点は以下の通りです。
- 集合オブジェクトの内部構造を隠すことができ、走査アルゴリズムを集合オブジェクトから切り離します。
- 異なる種類のコレクションオブジェクトを走査する標準化された方法を提供します。
- クライアントコードを簡素化し、より明確で簡潔にします。
- 異なる走査ニーズに適応するために異なるイテレーターの実装を提供することができます。
3. イテレーター パターンの実用例
イテレーターパターンには、次のような実用例があります。
- データベースクエリの結果セットを走査する。
- ファイルシステム内のファイルやフォルダを走査する。
- コレクション内の要素を走査する。
4. Golang でのイテレーター パターンの実装
4.1 UML クラス図
4.2 例の紹介
上記の UML クラス図では、主に Iterator と Collection の2つの役割があります。
- Iterator は、コレクションオブジェクトを走査するためのインターフェースを定義し、
HasNext()
メソッドで次の要素があるかどうかを判定し、Next()
メソッドで次の要素を取得します。 - ConcreteIterator は、Iterator の具体的な実装クラスであり、
HasNext()
とNext()
メソッドを実装します。 - Collection は、イテレーターオブジェクトを作成するためのインターフェースを定義し、
CreateIterator()
メソッドを備えています。 - ConcreteCollection は、Collection の具体的な実装クラスであり、
CreateIterator()
メソッドを実装します。
4.3 実装手順
次に、Golang でのイテレーターパターンの実装手順を段階的に説明します。
4.3.1 イテレーター インターフェースと具体的なイテレータークラスを定義する
type Iterator interface {
HasNext() bool
Next() interface{}
}
type ConcreteIterator struct {
collection *ConcreteCollection
index int
}
func (it *ConcreteIterator) HasNext() bool {
if it.index < len(it.collection.items) {
return true
}
return false
}
func (it *ConcreteIterator) Next() interface{} {
if it.HasNext() {
item := it.collection.items[it.index]
it.index++
return item
}
return nil
}
4.3.2 イテラブルオブジェクトのインターフェースと具体的なイテラブルオブジェクトクラスを定義する
type Collection interface {
CreateIterator() Iterator
}
type ConcreteCollection struct {
items []interface{}
}
func (c *ConcreteCollection) CreateIterator() Iterator {
return &ConcreteIterator{
collection: c,
index: 0,
}
}
4.3.3 イテラブルオブジェクトクラスでイテレーターの生成ロジックを実装する
func main() {
collection := &ConcreteCollection{
items: []interface{}{"Golang", "Python", "Java"},
}
iterator := collection.CreateIterator()
for iterator.HasNext() {
item := iterator.Next()
fmt.Println(item)
}
}
上記のコードを実行すると、以下の出力が生成されます。
Golang
Python
Java
上記のコードでは、ConcreteCollection
クラスを定義し、 Collection
インターフェースを実装し、CreateIterator()
メソッドでイテレーターオブジェクトを返します。このイテレーターオブジェクトを main()
関数で使用して走査します。
4.4 実装ステップの拡張: ジェネレータ関数を使用してのイテレータの実装の単純化
Golangでは、ジェネレータ関数(yield
)を使用してイテレータの実装を簡素化することができます。以下はジェネレータ関数を使用した例です。
func GenerateItems() <-chan interface{} {
items := []interface{}{"Golang", "Python", "Java"}
out := make(chan interface{})
go func() {
defer close(out)
for _, item := range items {
out <- item
}
}()
return out
}
func main() {
for item := range GenerateItems() {
fmt.Println(item)
}
}
上記のコードでは、GenerateItems()
関数を定義して、読み取り専用チャネル(<-chan
)を返し、この関数内でyield
を使用して要素を順次チャネルに送信しています。main()
関数では、この読み取り専用チャネルを走査するためにrange
を使用し、要素の値を出力しています。
こうすることで、ジェネレータ関数を使用してイテレータの実装を簡素化することができます。