在Java中使用迭代器模式

首先

我打算读一本介绍GoF设计模式的《Java语言学习设计模式入门增补改订版》,并总结所学内容。

迭代器模式

迭代器是什么?

迭代器是英文中的一个词,意思是「反复者」。特别是在编程中,它指的是将对集合体顺序访问时的「指引物」抽象化和泛化的内容。仅仅凭这个描述,我觉得很难形象化,所以我再举个更具体的例子。对于那些写过像下面这样的循环语句,以显示数组array中所有元素的人来说,应该很多吧。

for (int i = 0; i < array.length; i++) {
  System.out.println(array[i]);
}

在这里,变量i作为数组array的索引,依次访问数组的元素。
像这样“循环并指向整个数组,进行遍历”的概念就是迭代器。

角色

image.png

界面 (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言語で学ぶデザインパターン入門
广告
将在 10 秒后关闭
bannerAds