こんにちは。久しぶりすぎる。
なかなかアウトプットの習慣って身につかないですねぇ。
ということで、ちょっとハードルを下げた投稿をコンスタントにしていこうと思ってます。
最近GoFデザインパターンとSpringを勉強しているのでその投稿をしていこーと思ってます。
今日はIteratorパターンについて。
簡単なようで重要な概念。
Iteratorとは
Wikipediaには下記のように書いてある。
イテレータ(英語: iterator)とは、プログラミング言語において配列やそれに類似する集合的データ構造(コレクションあるいはコンテナ)の各要素に対する繰り返し処理の抽象化である。
つまり、データが集まっている空間の一つ一つの要素を最初から順番に順番に走査すること。
今から紹介する、Iteratorパターンとは、何かがたくさん集まっているときに、それを順番に指し示していき、全体をスキャンしていく処理を一般化したものをいう。
登場オブジェクト
- Aggregateインターフェース
- 数え上げを行われる対象物「集合体」を表す。
public interface Aggregate {
public abstract Iterator iterator();
}
- Iteratorインターフェース
- 要素の数え上げを行うもの。
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
- Aggregate実装クラス(ConcreateAggregate)
- Iterator実装クラス (ConcreateIterator)
上記のパターンを具体的に落とし込むと下記のようなものがあるだろう。
- Aggregateインターフェース
- Iteratorインターフェース
- Aggregate実装クラス(Parking)
- Iterator実装クラス (ParkingIterator)
- モデル(Car)
名前 | 解説 |
---|---|
Aggregate | 集合体を表すインタフェース |
Iterator | 数え上げ、スキャンを行うインタフェース |
Parking | 駐車場を表すAggregateの実装を行うクラス |
ParkingIterator | 駐車場をスキャンするクラス |
Car | 車を表すクラス |
サンプルコード
public class Parking implements Aggregate {
private Car[] cars;
private int last = 0;
public Parking(int maxsize) {
this.cars = new Car[maxsize];
}
public Car getCarAt(int index) {
return cars[index];
}
public void appendCar(Car car) {
this.cars[last] = car;
last++;
}
public int getLength() {
return last;
}
public Iterator iterator() {
return new ParkingIterator(this);
}
}
public class ParkingIterator implements Iterator {
private Parking parking;
private int index;
public ParkingIterator(Parking parking) {
this.parking = parking;
this.index = 0;
}
public boolean hasNext() {
if(index < parking.getLength()) {
return true;
} else {
return false;
}
}
public Object next() {
Car car = parking.getCarAt(index);
index++;
return car;
}
}
public class Car {
private String name;
private String color;
public Car(String name, String color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public String getColor() {
return color;
}
細かいメソッドの説明は省略するが、重要なメソッドは
- iterator
- hasNext
- next
の3つであろう。
iteratorメソッド
このメソッドは、Parkingクラスに対応するIteratorとして、ParkingIteratorというクラスのインスタンスを生成してそれを返す。この駐車場の車を数え上げたいときに、このiteratorメソッドが呼び出される。
hasNextメソッド
「次の車」があるかどうかを調べ、あるならtrue, ないならfalseを返す。
nextメソッド
Iteratorパターンを利用するメリット
実際、Iteratorパターンを利用せずとも for文やWhile文で同じ全体走査は可能である。
ではなぜわざわざインターフェースなどを用いて実装するのだろうか。
その理由は**「実装とは切り離して、数え上げが行うことができる」**からである。
while (it.hasNext()) {
Car car = (Car) it.next();
System.out.println(car.getName());
}
上記の例を見ると、使われているのは"next"と"hasNext"というメソッドだけであり、Parkingの実装で使われているメソッドは呼び出されていない。つまり、このコードはParkingの実装には依存しない。
例えば、今Parkingの中にはCarsという配列を使われているが、これをVectorを使うようにプログラムを修正したとしよう。この場合でも、Parkingがiteratorメソッドを持っており、正しいIteratorを返してくれれば上記のコードを変更する必要はない。
Iteratorがなかったら・・・
int i = 0;
while (i < parking.getLength()) {
Car car = parking.getCarAt(i);
System.out.println(car.getName());
}
と書けると思うんですが、問題ないよなぁ。としみじみ。Iteratorいらんやん。。。
色々調べると納得したので下で記述
もし、Carsの長さがこの時点で決まっていたら、parking.getLength()が発動できるが、未定だった場合上限が決められない。
それに対して、Iteratorの場合は「次の要素があるかないか」ということを調べるのでコレクションのようなサイズが未定なものでも使うことができる。言い換えると、上記のコードはParkingに依存しているといえる。依存は嫌ぁぁぁ。
まとめ
Iteratorパターンとは
集合体を順番に指し示していき、全体をスキャンしていく処理を一般化したもの。
目的は、クラスの再利用かを促進するためである。
デザインパターンって難しい。
何が難しいかって、一人でコーディングするときは意識しないよね。
ゴリゴリに書いてしまええええって思っていたので・・・。
そしてもっと短くわかりやすくコンパクトに書きたい・・・・。
次はその辺を挑戦する。
今日はこの辺で。