LoginSignup
16
11

More than 5 years have passed since last update.

C#に元々ある機能で学ぶデザインパターン "Iterator Pattern"

Posted at

概要

何番煎じか分かりませんが、イテレータパターン(Iterator Pattern)のお話です。
C#においては、言語に組み込まれていると言って良いでしょう。
Iterator パターン @ Wikipediaのクラス図に合わせた形で、C#の機能を説明していきます。

Aggregate -----------------> Iterator
    △                          △
    │                           │
Concrete                     Concrete
Aggregate -----------------> Iterator

IEnumerator<T>

デザインパターンで出てくるIteratorインタフェースは、C#ではIEnumerator<T>に当たります。
『列挙する者』みたいな意味(Enumurate + -or)ですね。

Current,MoveNext()

next(),hasNext()は、C#ではCurrent,MoveNext()のように少し違った形で実装されます。

interface IEnumerator<out T> {
    // 現在の要素を取得する。
    T Current { get; }
    // 次の要素に移動する。次の要素があればtrue,無ければfalseを返す。
    bool MoveNext();
    // その他の定義は省略
}

IEnumerable<T>

デザインパターンで出てくるAggregateインタフェースは、C#ではIEnumerable<T>に当たります。
『列挙可能』みたいな意味(Enumurate + -able)ですね。

GetEnumerator()

iterator()メソッドは、C#ではGetEnumerator()に当たります。

interface IEnumerable<out T> {
    // イテレータを取得
    IEnumerator<T> GetEnumerator();
    // その他の定義は省略
}

IEnumerable<T>を実装した型

ConcreteAggregateに当たるC#の型は無数にあります。
同一の型のインスタンスを複数扱うようなデータ型はほぼこれに当てはまると思って良いでしょう。

  • 配列
  • List<T>
  • Dictionary<TKey,TValue>

IEnumerator<T>を実装した型

IEnumerator<T>を実装した型は、例えばList<int>.Enumerator型などがあります。
ただ、こちらは実装型を意識せずに利用することが普通ですね。

組み込まれている機能

foreach構文

foreach構文では、GetEnumerator()メソッドを持つインスタンスであれば、同一の構文で要素を列挙できます。
これはC#プログラマなら無意識レベルで使っているであろう例です。

foreach (var item in obj) {
    Console.WriteLine(item);
}

↑の構文は↓とほぼ同義になります。

var iterator = obj.GetEnumerator();
while (iterator.MoveNext()) {
    Console.WriteLine(iterator.Current);
}
// 実際には例外処理や後処理などがあるが、ここでは省略

LINQ

LINQ to Objectでは、IEnumerable<T>を『流れるようなインタフェース』として扱うことで、様々な標準クエリを利用可能にしています。

Enumerable
   .Range(3, 10)
   .Where(i => i % 2 == 1)
   .Select(i => new { A = i, B = i * i / 2, C = i * i / 2 + 1 })
   .ToList()
   .ForEach(Console.WriteLine);

ジェネレータ

C#ではIEnumerable<T>を利用したイテレータを生成するための構文が用意されています。
自前でIEnumerable<T>IEnumerator<T>を作成する手間は基本的に不要と言えます。
(少しややこしいのですが、この構文は"Iterator block"と呼ばれます。)

// イテレータ構文と呼ばれているが、実際にはジェネレータ
static IEnumerable<int> Generate5Primes() {
    yield return 2;
    yield return 3;
    yield return 5;
    yield return 7;
    yield return 11;
}

// 無限ループも使い方次第
static IEnumerable<double> RandomDoubles() {
    var random = new Random();
    while (true) {
        yield return random.NextDouble();
    }
}

まとめ

"Gang of Four"によるデザインパターンの紹介が1994年のことになります。つまり、C#に限らずその後にリリースされた言語ではこれらのデザインパターンが言語に取り込まれていることも多いのです。
これからデザインパターンを勉強しようとしている人は、自分の得意とする言語(やフレームワーク)にどのようなデザインパターンが組み込まれているのかを調べてみると良いと思います。

16
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
11