イテレータパターンは、コレクション(配列やリストなど)の内部構造を隠蔽しつつ、要素を順番に走査する方法を提供するデザインパターンです。
C#を例に具体的な実装を紹介しますが、JavaやPythonなど他の言語でも応用できます。このパターンを使うことで、異なるデータ構造に対して統一的なアクセス手法を確立し、柔軟な設計が可能になります。
イテレータパターンとは?
イテレータパターン(Iterator Pattern)は、オブジェクトの集合(コレクション)の要素に順番にアクセスするための設計手法です。
通常、配列やリストなどのデータ構造を直接操作すると、その内部実装に依存してしまいます。しかし、イテレータパターンを使えば、データ構造の詳細を隠しながら、統一的な方法でデータを扱えます。
イテレータパターンのメリット
イテレータパターンを採用することで、以下のようなメリットがあります。
- データ構造を意識せずに要素を取得できる
- 異なるコレクション型を統一的に扱える
- 要素の取得方法を柔軟にカスタマイズ可能
- 拡張性が向上し、コードの可読性が高まる
C#でのイテレータパターンの実装
C#では、IEnumerable<T>
インターフェースを利用してイテレータパターンを簡単に実装できます。
以下では、独自のコレクションクラスを作成し、カスタムイテレータを実装する方法を紹介します。
1. コレクションを表すクラス
まず、IEnumerable<T>
を実装したカスタムコレクションクラスを作成します。
using System;
using System.Collections;
using System.Collections.Generic;
// カスタムコレクション
class CustomCollection<T> : IEnumerable<T>
{
private List<T> _items = new List<T>();
// 要素を追加するメソッド
public void Add(T item) => _items.Add(item);
// イテレータを取得
public IEnumerator<T> GetEnumerator() => new CustomIterator<T>(_items);
// 非ジェネリック版のGetEnumerator(IEnumerableの実装)
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
IEnumerable<T>
を実装すると、C#の foreach
を使って要素を簡単にループできます。
2. イテレータを表すクラス
次に、IEnumerator<T>
を実装して、カスタムイテレータを作成します。
// カスタムイテレータ
class CustomIterator<T> : IEnumerator<T>
{
private List<T> _items;
private int _position = -1;
public CustomIterator(List<T> items) => _items = items;
// 現在の要素を取得
public T Current => _items[_position];
object IEnumerator.Current => Current;
// 次の要素へ移動
public bool MoveNext()
{
if (_position + 1 < _items.Count)
{
_position++;
return true;
}
return false;
}
// イテレータをリセット
public void Reset() => _position = -1;
// リソースの解放(今回は特に不要)
public void Dispose() { }
}
MoveNext()
で次の要素に進み、Current
で現在の要素を取得します。
3. 実際の使用例
作成したカスタムコレクションを使って、foreach
で要素を取得してみます。
class Program
{
static void Main()
{
CustomCollection<string> collection = new CustomCollection<string>();
collection.Add("Apple");
collection.Add("Banana");
collection.Add("Cherry");
foreach (var item in collection) // イテレータが内部的に動作
{
Console.WriteLine(item);
}
}
}
Apple
Banana
Cherry
4. C#のyield return
を使った簡単な実装
C#では、IEnumerator<T>
を直接実装しなくても、yield return
を使うことで簡単にイテレータを作成できます。
using System;
using System.Collections.Generic;
// カスタムコレクション
class CustomCollection<T>
{
private List<T> _items = new List<T>();
public void Add(T item) => _items.Add(item);
// `yield return` を使った簡単なイテレータ
public IEnumerable<T> GetItems()
{
foreach (var item in _items)
{
yield return item; // 要素を順番に返す
}
}
}
class Program
{
static void Main()
{
CustomCollection<string> collection = new CustomCollection<string>();
collection.Add("Dog");
collection.Add("Cat");
collection.Add("Rabbit");
foreach (var item in collection.GetItems())
{
Console.WriteLine(item);
}
}
}
Dog
Cat
Rabbit
yield return
を使うと、IEnumerator<T>
の実装が不要になり、シンプルなコードでイテレータを実現できます。
IEnumerable<T>
を実装すると、foreach
でループできるようになるIEnumerator<T>
を使うと、カスタムイテレータを作成できるyield return
を使えば、簡単にイテレータを作れる- データ構造を意識せずに統一的な方法で要素を走査できる
イテレータパターンを使うことで、コードの再利用性が向上し、異なるデータ構造を一貫した方法で扱うことができます!
イテレータパターンを使うべきケース
イテレータパターンは、以下のような状況で特に有効です。
- 異なるデータ構造(リスト、配列、ツリー、グラフなど)を統一的に走査したいとき
- データ構造の内部実装を隠蔽し、安全にアクセスさせたいとき
- 独自のルールで要素の取得順序やフィルタリングをしたいとき
foreach
などの構文を自作のコレクションで利用したいとき- 順番にアクセスする処理を統一し、コードの可読性と拡張性を向上させたいとき
このパターンを使うことで、データ構造に依存しない柔軟な設計が可能になります。
まとめ
- イテレータパターンは、データ構造を意識せずに要素を順番に走査するためのデザインパターン。
IEnumerable<T>
を実装すると、foreach
で統一的にデータを扱える。IEnumerator<T>
を使えば、カスタムイテレータを作成できる。yield return
を活用すると、簡潔なコードでイテレータを実装可能。- 異なるデータ構造(リスト、ツリー、グラフなど)でも、統一的なアクセスが可能になり、コードの可読性・拡張性が向上する。
イテレータパターンを活用すると、異なるデータ構造を統一的に扱え、コードの柔軟性や再利用性が向上します。特に、foreach
を使えるようにしたり、データアクセスをカプセル化することで、保守性の高いプログラムを実現できます。
C#では IEnumerable<T>
や yield return
を活用することで、簡単にイテレータを実装できるため、ぜひ実践してみてください!