導入
Processingがバージョン3.
閑話休題。今回はGoFによるデザインパターン23種類のうち、
展開
Iterator(イテレータ)
前述したように、
Iteratorパターンの目的
iterateは
オブジェクトの集合を取り扱う際、
String names[] = {"Tim Bray", // 0番目の要素
"Brian Kernighan", // 1番目の要素
"Jon Bentley", // 2番目の要素
"Karl Fogel"}; // 3番目の要素
for(int i = 0; i < names.length; ++i){
println(names[i]);
}Java言語、
for(String v : names){ println(v); } 上のコード例ではIteratorパターンの存在が隠されています。このコードの裏ではIteratorパターンを利用して配列の要素の先頭から順にアクセスしています。
Iteratorパターンを使うと、
- 「
names[i]として、配列というデータ構造の変数 namesの、
先頭からi番目に納められたString型のデータ」
とアクセスしていたところが、
- 「
String型のデータv」
で済みます。Iteratorパターンに従っていることが分かれば、
[Iteratorパターン]
複数のオブジェクトを順に取り扱う機能を抽象化したもの。
Java言語やProcessingでは、
GoFによるIteratorパターンの全体像
ここでは、
Java言語のクラスライブラリ中で実装されているIteratorパターンは、
下図はIteratorパターンを用いたコードのクラス図の一例です。
Iteratroパターンでは、ConcreteAggregateクラスに納められたデータの集合をClientクラスが順に取り出して処理することを目的とします。図の一番下にあるDataクラスが、ConcreteAggregateクラスが保持するデータ保管用クラスです。Aggregateという英語は
Aggregateインタフェイスのiteratorメソッドは、Iteratorインタフェイスを実装したConcreteIteratorオブジェクトを返します。ConcreteIteratorはConcreteAggregateに納められたオブジェクト群にアクセスするコードを持っています。
結局Clientクラスがデータのアクセスに必要とするのは、ConcreteAggregateオブジェクトと、ConcreteIteratorオブジェクトの参照を持つIteratorインタフェイスのオブジェクトです。
[Clientクラスがデータアクセスに必要とする情報] - ConcreteAggregateオブジェクトへの参照
- ConcreteAggregateオブジェクトのiteratorメソッドが返すConcreteIteratorへの参照
Iteratorパターンのメリット
この仕組みがあれば、ConcreteAggregateクラスがどんな型やクラスのオブジェクト群を保持していても、Clientクラスから、Iteratorインタフェイスの持つhasNextメソッドやnextメソッドでオブジェクト群の巡回が可能になります。仮にConcreteAggregateクラスが保持するオブジェクトの型が変更されても、ConcreteIteratorクラスのコードを修正しておけば、Clientクラスのコードでは、ConcreteAggregateクラスの保持するデータの巡回のためのコードに変更が必要ありません。
チームでコーディングしている際に、ConcreteAggregateクラス側の開発者も、
例えば、
「このクラスはIteratorパターンに従っています」
と言えば、iteratorメソッドがあり、ConcreteIteratorのオブジェクトを取得できるとわかります。後は、nextメソッドでオブジェクトを取得し、hasNextメソッドで次のオブジェクトが取得可能かを知ることができます。
Java言語では、ConcreteIteratorにあたるオブジェクトを返すメソッドiteratorを実装しているクラスArrayListやVectorなど)iteratorメソッドを実装しなさいよ、Aggregateインタフェイスにあたるのが、Iterable<T>インタフェイスです。
ですから、ConcreteIteratorクラスを書かなくても、Clientクラスからオブジェクトを巡回するコードを簡単に書けるのです。
Java言語やProcessingで使われているIteratorパターンを見る
次のサンプルコードを見てください。
import java.util.Arrays;
import java.util.Iterator;
ArrayList<String> A = new ArrayList(Arrays.asList("Tim Bray",
"Brian Kernighan",
"Jon Bentley",
"Karl Fogel"));
println("**Iteratorパターンを使わない**"); // (1)
for(int i = 0; i < A.size(); i++){
println(A.get(i));
}
println("**拡張for文。内部でIteratorパターンを使っている**"); // (2)
for(String v : A){
println(v);
}
println("**明示的にIteratorパターンを使う**"); // (3)
Iterator it = A.iterator();
while(it.hasNext()){
println(it.next());
}Stringクラスのデータを納めるArrayListオブジェクトAを宣言し、
(1)は、iを用いて要素を指定します。
(2)は、
(3)は、
注目してもらいたいのは、String型のArrayListのAである」String型のオブジェクトvである」AからConcreteIteratorオブジェクトへの参照を取得した後は、ConcreteIteratorオブジェクトの取得先を切り替えれば、
あなたのコードにGoFのIteratorパターンを使う
それでは、ADrawToolとします。
- Iteratorパターンを適用したsketch
これにより、ExStatechartDiagram2.のdrawメソッド内のコードでは隠れていたIteratorが、ADrawTool.では表に引っ張りだされました。
ExStatechartDiagram2.pde より for(Point p : dots){
point((int)p.getX() * rate,(int)p.getY() * rate);
}ADrawTool.pde より Iterator it = ca.iterator();
while(it.hasNext()){
Point p = (Point)it.next();
point((int)p.getX() * rate,(int)p.getY() * rate);
}これらのサンプルコードでは、Pointクラスのオブジェクトpに格納して点を描画するだけです。ExStatechartDiagram2.では、ArrayListが持っていたJava言語の持つIteratorパターンを利用した拡張for文を使ってデータを巡回するだけで事足りていました。
caはGoFによるIteratorパターンのAggregateインタフェイスを実装したConcreteAggregateクラスのオブジェクトですから、iteratorメソッドを持ちます。このiteratorメソッドを呼ぶと、Iteratorインタフェイスを実装したConcreteIteratorクラスのオブジェクトを返します。Iteratorインタフェイスのオブジェクトitが持つConcreteIteratorオブジェクトへの参照を用いて、whileループ内で各点の示すディスプレイウインドウ内の座標に点を描きます。
GoFによるデザインパターンのIteratorを忠実に適用したので、ADrawTool.のコードは冗長になっています。これだけではIteratorパターンを見える化した利益はありません。
このADrawTool.を発展させ、Iteratorインタフェイスを使っていると、Iteratorインタフェイスがほしくなります。
それでは独自のIteratorパターンを用いるメリットがある活動に入ります。データ群を逆順に巡回するための、hasPreviouspreviousgoTailメソッドとしましょう。それならば、goHeadメソッドとします。これらをインタフェイスIteratorに用意し、ConcreteIteratorへ実装しましょう。これらのメソッドを実装するクラスは、Client側にあたるADrawToolのコードからはIteratorインタフェイスを通じて、caにアクセスできます。Iteratorパターンを利用する側のコードは、
演習
演習1(難易度:middle)
sketchADrawToolのIteratorインタフェイスにhasPrevious, previous, goHead, goTailの各メソッド宣言を用意し、ConcreteIteratorクラスにそれらを実装しましょう。
まとめ
- Iteratorパターンのメリットと使い方を学びました。
学習の確認
それぞれの項目で、
- Iteratorパターンのメリットがわかりましたか?
- わかりました。自分のプログラミングにも活用したい。
- 解説を理解することはできたが、
それほどメリットを感じない。 - 本文が理解できない。
- Iteratorパターンを使えるようになりましたか?
- 使えるようになった。自分のプログラミングにも活用できそうだ。
- 本文の例を理解することはできたが、
自分のプログラミングに活用できる気がしない。 - 本文の例が理解できない。
参考文献
- 『増補改訂版Java言語で学ぶデザインパターン入門』
(結城浩 著、 ソフトバンククリエイティブ) - 誰もが認める最も分かりやすいデザインパターン入門書。本来は原典
(GoF本) を勧めるべきところですが、 本書は別格。
- 誰もが認める最も分かりやすいデザインパターン入門書。本来は原典
- 『オブジェクト指向における再利用のためのデザインパターン』
(Eric Gamma 著、 ソフトバンククリエイティブ) - デザインパターンの原典。別称
『GoF本』 サンプルコードがC++で書かれているため、 ProcessingやJava言語のユーザにはハンディがあります。しかし結城浩氏の入門書を読みこなした後ならば本書にあたる価値があります。
- デザインパターンの原典。別称
- 『Java デザインパターン徹底攻略』
(日立ソフトウェアエンジニアリング (株) インターネットビジネス部 著、 技術評論社) - 流石の日立。前掲のGoF本の解説書で、
サンプルはJava言語。絶版であることが惜しまれます。強く再版を望みます。
- 流石の日立。前掲のGoF本の解説書で、
演習解答
- 追加した
hasPrevious,previous,goHead,goTailが動作するかをチェックするテストコードConcreteIteratorTest.を追加しています。pde
