在Java中使用迭代器模式
首先
我打算读一本介绍GoF设计模式的《Java语言学习设计模式入门增补改订版》,并总结所学内容。
迭代器模式
迭代器是什么?
迭代器是英文中的一个词,意思是「反复者」。特别是在编程中,它指的是将对集合体顺序访问时的「指引物」抽象化和泛化的内容。仅仅凭这个描述,我觉得很难形象化,所以我再举个更具体的例子。对于那些写过像下面这样的循环语句,以显示数组array中所有元素的人来说,应该很多吧。
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
在这里,变量i作为数组array的索引,依次访问数组的元素。
像这样“循环并指向整个数组,进行遍历”的概念就是迭代器。
角色

界面 (jiè
Aggreate
数え上げを行う対象の「集合体」を表します。
メソッドとしてはIterator()のみを持ちます。
これはIterator生成するために使用します。
public interface Aggregate {
public abstract Iterator iterator();
}
Iterator
集合の要素の「数え上げを行うもの」を表します。
メソッドとしてはhasNext()とnext()の2つを持ちます。
hasNext()は次の要素を持つかどうかを確認するために使用します。
next()は次の要素があった際に次の要素を取得するために使用します。
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
实现类
实现接口并编写具体处理。关于具体例子,我们将在后面进行说明。
-
- ConcreateAggreate
- ConcreateIterator
具体例子
以下是关于”将员工进行分类的员工列表” 和”员工列表的迭代器”的具体例子说明。
实现类
Employeeクラス
Employee(従業員)クラスは集合体の要素を表します。
名前と従業員コードを持ちます。
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を生成して返しています。
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()で従業員リストの次の要素(従業員)を返却しています。
順次にアクセスを行う方法は様々ですが、今回は単純に前から順次でアクセスする実装を行います。
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クラス
従業員リストに従業員を追加し、追加した従業員の名前と従業員コードを従業員リストから出力しています。
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的结果如下所示。
可以确认员工列表按添加顺序正确输出。
Tarou_Tanaka:C001
Hanako_Yamada:C002
Yuuya_Suzuki:C003
Kanako_Satou:C004
优点
通过使用Iterator,您无需关注集合体是什么样的集合体(例如数组、ArrayList、Vector等),以及进行了怎样的实现,即可进行计数。以下是将集合体从数组更改为ArrayList的EmployeeList.class的定义。在这种情况下,您无需修改执行类Main.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);
}
}
Tarou_Tanaka:C001
Hanako_Yamada:C002
Yuuya_Suzuki:C003
Kanako_Satou:C004
额外添加 (2018/10/31)
除了按照顺序逐个访问,Iterator还有各种其他访问方法(例如逆序、跳跃一个等等)。这次我们在ArrayList中添加了可以逆序访问的Iterator。只展示有差异的类,请在总结中确认其他类。
接口
Aggregate
逆順にアクセスするIteratorを生成するreverseIterator()を追加しています。
public interface Aggregate {
public abstract Iterator iterator();
public abstract Iterator reverseIterator();
}
实现类
EmployeeListクラス
reverseIterator()を追加しています。
reverseIterator()において自身を引数としてEmployeeListReverseIteratorを生成して返しています。
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が発生します。
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を追加し、順次で出力をした後、逆順で出力を行っています。
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サンプルコード
此外,关于其他设计模式的信息我已经在下面做了总结,也请您参考一下。
- [随時更新]Javaでデザインパターンまとめ
可以提供写论文所需的所有信息和引用文献。
- 増補改訂版 Java言語で学ぶデザインパターン入門