IteratorによるUIの分離
ユーザインタフェースを持つアプリケーションを書く場合、UI部分とロジックをうまく分離できないことがあります。たとえば、コンソールから数値を入力し、その平均値を求めるようなことを考えてみます。
using System; class Program { static void Main () { int sum = 0; int cnt = 0; Console.WriteLine ("Input number:"); while (true) { string input = Console.ReadLine (); if (input.ToUpper() == "Z") break; int n; if (Int32.TryParse (input, out n)) { sum += n; ++cnt; } } if (cnt > 0) Console.WriteLine ("Average = {0}", sum / cnt); } }
このコードだとロジックがコンソールに依存してしまい、たとえば、数値をファイルから読み出すような変更があった場合、大きく書き換えることになります。代案としては、ユーザが入力した値を配列に入れて、後で一括して処理するなどがあります。しかし、ユーザからの入力は件数がわからないので、動的配列を用意して保存する必要があり、メモリがもったいない気がします。こんな時には、Iteratorを使うと便利です。
先ほどのコードをIteratorを使って書き換えてみます。
using System; using System.Collections.Generic; class Program { static IEnumerable<int> Input () { while (true) { string input = Console.ReadLine (); if (input.ToUpper() == "Z") yield break; int n; if (Int32.TryParse (input, out n)) yield return n; } } static void Main () { int sum = 0; int cnt = 0; Console.WriteLine ("Input number:"); foreach (int n in Input ()) { sum += n; ++cnt; } if (cnt > 0) Console.WriteLine ("Average = {0}", sum / cnt); } }
こんな感じ。動的配列も不要です。Iteratorを使うと状態マシンを簡単に作れるので、とても便利ですよ〜