JavaでIteratorパターン

# はじめに
[GoF](https://ja.wikipedia.org/wiki/ギャング・オブ・フォー_(情報工学))のデザインパターンを紹介している[『増補改訂版 Java言語で学ぶデザインパターン入門』](https://www.amazon.co.jp/増補改訂版Java言語で学ぶデザインパターン入門-結城-浩/dp/4797327030/ref=pd_lpo_sbs_14_t_0?_encoding=UTF8&psc=1&refRID=2ZE4GPYNN55JGDR5QMHP)を読んで、学んだ内容についてまとめます。

# Iteratorパターン
## Iteratorとは
Iteratorとは英単語で日本語では「**反復子**」を意味します。
特にプログラミングにおいては、集合体に対して順次にアクセスを行う際に、「**指し示すもの**」を抽象化し、一般化したものを意味します。
この説明だけではイメージが掴みにくいと思うので、もう少し具体的な例をあげます。
以下のような配列`array`の要素を全て表示するような繰り返し文を書いたことがある人は多いのではないでしょうか。

```java:sample.java
for (int i = 0; i < array.length; i++) {
  System.out.println(array[i]);
}
```
ここで変数`i`は配列`array`の添え字となり、配列の持つ要素に順次にアクセスを行っています。
このように「**繰り返して全体を指し示し、走査を行う**」ものがIteratorです。

## 登場人物
Itaratorパターンで使用するのは以下のクラス図に登場するクラスとインターフェースです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/278934/0d30936c-345c-d691-c216-1fd6d8ff5dd9.png)

### インターフェース
- **Aggreate**  
数え上げを行う対象の「集合体」を表します。  
メソッドとしては`Iterator()`のみを持ちます。  
これはIterator生成するために使用します。

```java:Aggregate.java
public interface Aggregate {
	public abstract Iterator iterator();
}
```
- **Iterator**  
集合の要素の「数え上げを行うもの」を表します。  
メソッドとしては`hasNext()`と`next()`の2つを持ちます。  
`hasNext()`は次の要素を持つかどうかを確認するために使用します。  
`next()`は次の要素があった際に次の要素を取得するために使用します。  

```java:Iterator.java
public interface Iterator {
	public abstract boolean hasNext();

	public abstract Object next();
}
```

### 実装クラス
インターフェースを実装し、具体的な処理を記述します。
具体例については後述いたします。

- **ConcreateAggreate**
- **ConcreateIterator**

## 具体例
具体例として、「**従業員をまとめる従業員リスト**」と「**従業員リストのIterator**」をもとに説明します。
### 実装クラス
- **Employeeクラス**  
Employee(従業員)クラスは集合体の要素を表します。  
名前と従業員コードを持ちます。

```java:Employee.java
public class Employee {
	private String name;
	private String employeeCode;

	public Employee(String name, String employeeCode) {
		this.name = name;
		this.employeeCode = employeeCode;
	}

	public String getName() {
		return name;
	}

	public String getEmployeeCode() {
		return employeeCode;
	}
}
```

- **EmployeeListクラス**  
EmployeeList(従業員リスト)クラスは従業員の集合体を表します。  
従業員の配列と添え字を持ちます。  
`iterator()`において自身を引数として`EmployeeListIterator`を生成して返しています。

```java:EmployeeList.java
public class EmployeeList implements Aggregate {
	private Employee[] employees;
	private int last = 0;

	public EmployeeList(int maxsize) {
		this.employees = new Employee[maxsize];
	}

	public Employee getEmployeeAt(int index) {
		return employees[index];
	}

	public void appendEmployee(Employee employee) {
		this.employees[last] = employee;
		last++;
	}

	public int getLength() {
		return last;
	}

	public Iterator iterator() {
		return new EmployeeListIterator(this);
	}
}
```

- **EmployeeListIteratorクラス**  
EmployeeListIterator(従業員リストIterator)クラスは従業員の集合体を数え上げるものを表します。  
従業員リストと添え字を持ちます。  
`hasNext()`で従業員リストが次の要素を持つかを確認し、`next()`で従業員リストの次の要素(従業員)を返却しています。
順次にアクセスを行う方法は様々ですが、今回は単純に**前から順次**でアクセスする実装を行います。

```java:EmployeeListIterator.java
public class EmployeeListIterator implements Iterator {
	private EmployeeList employeeList;
	private int index;

	public EmployeeListIterator(EmployeeList employeeList) {
		this.employeeList = employeeList;
		this.index = 0;
	}

	public boolean hasNext() {
		if (index < employeeList.getLength()) {
			return true;
		} else {
			return false;
		}
	}

	public Object next() {
		Employee employee = employeeList.getEmployeeAt(index);
		index++;
		return employee;
	}
}
```
### 実行クラス
- **Mainクラス**  
従業員リストに従業員を追加し、追加した従業員の名前と従業員コードを従業員リストから出力しています。

```java:Main.java
public class Main {
	public static void main(String[] args) {
		EmployeeList employeeList = new EmployeeList(4);
		employeeList.appendEmployee(new Employee("Tarou_Tanaka", "C001"));
		employeeList.appendEmployee(new Employee("Hanako_Yamada", "C002"));
		employeeList.appendEmployee(new Employee("Yuuya_Suzuki", "C003"));
		employeeList.appendEmployee(new Employee("Kanako_Satou", "C004"));
		Iterator it = employeeList.iterator();
		while (it.hasNext()) {
			Employee employee = (Employee) it.next();
			System.out.println(employee.getName() + ":" + employee.getEmployeeCode());
		}
	}
}
```
### 実行結果
`Main.class`を実行した結果は以下になります。
`employeeList`に追加した順にきちんと出力されていることが確認できます。

```:実行結果
Tarou_Tanaka:C001
Hanako_Yamada:C002
Yuuya_Suzuki:C003
Kanako_Satou:C004
```

## メリット
Iteratorを使用することで数え上げを行う際に集合体がどのような集合体であるか(配列、ArrayList、Vectorなど)、どのような実装が行われているかを意識する必要がなくなります。 
以下で集合体を配列からArrayListに変更した`EmployeeList.class`を定義します。 
この時、実行クラスの`Main.class`を修正する必要はなく、実行結果は配列の場合と同様です。

```java:EmployeeList.java
import java.util.ArrayList;

public class EmployeeList implements Aggregate {
	private ArrayList<Employee> employees;

	public EmployeeList(int initialsize) {
		this.employees = new ArrayList<>(initialsize);
	}

	public Employee getEmployeeAt(int index) {
		return (Employee) employees.get(index);
	}

	public void appendEmployee(Employee employee) {
		employees.add(employee);
	}

	public int getLength() {
		return employees.size();
	}

	public Iterator iterator() {
		return new EmployeeListIterator(this);
	}
}
```
```:実行結果
Tarou_Tanaka:C001
Hanako_Yamada:C002
Yuuya_Suzuki:C003
Kanako_Satou:C004
```

# 追記　(2018/10/31)
Iteratorには前から順次でアクセスする以外にも様々なアクセス方法があります。(逆順、1つ飛ばしなど) 
今回はArrayListで逆順でアクセスするIteratorを追加いたしました。
差分のあるクラスのみ掲載しますので、その他のクラスについては[まとめ](https://qiita.com/mk777/items/398bd26de44eac4f383b#%E3%81%BE%E3%81%A8%E3%82%81)で確認してください。

## インタフェース
- **Aggregate**  
逆順にアクセスするIteratorを生成する`reverseIterator()`を追加しています。

```java:Aggregate.class
public interface Aggregate {
	public abstract Iterator iterator();

	public abstract Iterator reverseIterator();
}
```
## 実装クラス
- **EmployeeListクラス**  
`reverseIterator()`を追加しています。  
`reverseIterator()`において自身を引数として`EmployeeListReverseIterator`を生成して返しています。

```java:EmployeeList.class
import java.util.ArrayList;

public class EmployeeList implements Aggregate {
	private ArrayList<Employee> employees;

	public EmployeeList(int initialsize) {
		this.employees = new ArrayList<>(initialsize);
	}

	public Employee getEmployeeAt(int index) {
		return (Employee) employees.get(index);
	}

	public void appendEmployee(Employee employee) {
		employees.add(employee);
	}

	public int getLength() {
		return employees.size();
	}

	public Iterator iterator() {
		return new EmployeeListIterator(this);
	}

	public Iterator reverseIterator() {
		return new EmployeeListReverseIterator(this);
	}
}
```

- **EmployeeListReverseIteratorクラス**  
新規に作成するクラスですが、順次アクセスを行う`EmployeeListIterator.class`と同様に`hasNext()`と`next()`を実装しています。  
コンストラクタで`employeeList`の要素数から1を引いた数字を`index`に持ちます。  
これにより仮に要素数が5のリストからは4を取得することになります。  
`hasNext()`ではArrayListの要素の数だけ逆順からアクセスを行います。  
注意すべき点としては**ループの条件で`index`が0未満にならないようにする必要がある**ことです。  
この条件がなければ`next()`でemployeeList[-1]にアクセスしようとしてしまい`ArrayIndexOutOfBoundsException`が発生します。

```java:EmployeeListReverseIterator.class
public class EmployeeListReverseIterator implements Iterator {
	private EmployeeList employeeList;
	private int index;

	public EmployeeListReverseIterator(EmployeeList employeeList) {
		this.employeeList = employeeList;
		this.index = employeeList.getLength() - 1;
	}

	public boolean hasNext() {
		if (index < employeeList.getLength() && index >= 0) {
			return true;
		} else {
			return false;
		}
	}

	public Object next() {
		Employee employee = employeeList.getEmployeeAt(index);
		index--;
		return employee;
	}
}
```
## 実行クラス
- **Mainクラス**  
`EmployeeList`に`Employee`を追加し、順次で出力をした後、逆順で出力を行っています。

```java:Main.class
public class Main {
	public static void main(String[] args) {
		EmployeeList employeeList = new EmployeeList(4);
		employeeList.appendEmployee(new Employee("Tarou_Tanaka", "C001"));
		employeeList.appendEmployee(new Employee("Hanako_Yamada", "C002"));
		employeeList.appendEmployee(new Employee("Yuuya_Suzuki", "C003"));
		employeeList.appendEmployee(new Employee("Kanako_Satou", "C004"));
		Iterator it = employeeList.iterator();
		System.out.println("------- Order -------");
		while (it.hasNext()) {
			Employee employee = (Employee) it.next();
			System.out.println(employee.getName() + ":" + employee.getEmployeeCode());
		}
		System.out.println("------- Reverse Order -------");
		Iterator rit = employeeList.reverseIterator();
		while (rit.hasNext()) {
			Employee employee = (Employee) rit.next();
			System.out.println(employee.getName() + ":" + employee.getEmployeeCode());
		}
	}
}
```
## 実行結果
`Main.class`を実行した結果は以下になります。
`employeeList`に**追加した順**と、追加したものと**逆順**で出力されていることが確認できます。

```:実行結果
------- Order -------
Tarou_Tanaka:C001
Hanako_Yamada:C002
Yuuya_Suzuki:C003
Kanako_Satou:C004
------- Reverse Order -------
Kanako_Satou:C004
Yuuya_Suzuki:C003
Hanako_Yamada:C002
Tarou_Tanaka:C001
```

# まとめ
集合体に順次にアクセスを行うIteratorパターンに関して学びました。
以下でサンプルコードをアップしていますのでよろしければ参考にどうぞ。

- [Iteratorサンプルコード](https://github.com/masayuki777/study/tree/master/DesignPatterns/01_Iterator)

また、他のデザインパターンに関しては以下でまとめていますので、こちらも参考にどうぞ。

- [[随時更新]Javaでデザインパターンまとめ](https://qiita.com/mk777/items/4e13505b654fc21c76a2)

# 参考文献
- [増補改訂版 Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/増補改訂版Java言語で学ぶデザインパターン入門-結城-浩/dp/4797327030/ref=pd_lpo_sbs_14_t_0?_encoding=UTF8&psc=1&refRID=2ZE4GPYNN55JGDR5QMHP)