Java 程式範例來探討 Design Pattern: Iterator

作者:李元豪

Design pattern 是在物件導向軟體領域裡,對於一再出現的問題,長期演進而成的解決方案。其目地是讓你的程式設計更有彈性,更具可再利用性。“Gang of Four” 所著的「Design Patterns」在 Iterator 這個模式的章節裡,是用 C++ 示範,而且內容太豐富,以至於讓初學者不容易了解,現在我試著以 Java 程式來探討。

使用 Iterator 設計模式的動機與目地:

現在如有一個關於如何查詢「名冊」的問題,也就是要對一個「名字的聚合物件」來做巡訪。

不良的解決方式:

public class Person {
    private String name = "";
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

public class ConcreteAggregate  {
    private Person[] namecollection;
    private int last = 0;
    public ConcreteAggregate(int maxsize) {
        this.namecollection = new Person[maxsize];
    }
    public Person getPersonAt(int index) {
        return namecollection[index];
    }
    public void appendPerson(Person personName) {
        this.namecollection[last] = personName;
        last++;
    }
    public int getLength() {
        return last;
    }
}

public class IteratorExample1 {
    public static void main(String[] args) {
        ConcreteAggregate namecollection = new ConcreteAggregate(3);
        Person person;
        namecollection.appendPerson(new Person("Davis"));
        namecollection.appendPerson(new Person("Frank"));
        namecollection.appendPerson(new Person("Jeny"));
        for(int i=0; i<namecollection.getLength(); i++)
         { 
           person = namecollection.getPersonAt(i);
           System.out.println("" + person.getName());
         }
    }
}

看起來好像不錯,問題解決了,而且有點物件導向的味道,但 ConcreteAggregate 類別跟 Person 類別綁在一起,如果要換成其他類別的話,ConcreteAggregate 類別勢必要重寫,如果 ConcreteAggregate 類別裡的 Person[] namecollection,想換成 Vector 或 List 的話,那 IteratorExample1 類別的巡訪方式也要重寫,所以程式碼顯得沒有彈性,無法再利用。

利用 Iterator 模式來寫程式:

public interface Aggregate {
    public abstract Iterator iterator();
}

public interface Iterator {
    public abstract boolean hasNext();
    public abstract Object next();
}

import java.util.* ;
public class ConcreteAggregate implements Aggregate {
    private Object[] collection;
    //private Vector collection;
    private int last = 0;
    public ConcreteAggregate() {
        //collection = new Vector(3); 
        collection = new Object[3];
     }

    public Object getItemAt(int index) {
        return collection[index];
       //return ((Object)collection.get(index));
    }

    public void appendItem(Object item) {
        this.collection[last] = item;
        last++;
        //collection.add(item);
    }

    public int getLength() {
        return last;
        //return collection.capacity();
    }

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

public class ConcreteIterator implements Iterator {
    private ConcreteAggregate namecollection;
    private int index;
    public ConcreteIterator(ConcreteAggregate collection) {
        this.namecollection = collection;
        this.index = 0;
    }
    public boolean hasNext() {
        if (index < namecollection.getLength()) {
            return true;
        } else {
            return false;
          }
    }
    public Object next() {
        Object item = namecollection.getItemAt(index);
        index++;
        return item;
    }
}

public class IteratorExample2 {
    public static void main(String[] args) {
        ConcreteAggregate collection = new ConcreteAggregate();
        collection.appendItem(new Person("Davis"));
        collection.appendItem(new Person("Frank"));
        collection.appendItem(new Person("Jeny"));
        Iterator it = collection.iterator();
        while (it.hasNext()) {
            Person person = (Person)it.next();
            System.out.println("" + person.getName());
        }
    }
}

這個程式碼應該符合 Iterator 設計模式的動機與目地,不管聚合物件的內部結構是什麼 ConcreteIterator 類別不須更改,仍可存取物件;利用遺傳方式可增加多種巡訪聚合物件的方式;聚合物件改變時(如 Array 改成 Vector)ConcreteIterator 類別仍可用相同的介面來巡訪聚合物件。

補充:

Acera 談到:

這是不錯的個人心得交流文章,已經有那種味道了。因為是心得交流,就是對原文進一步的說明,讓初學者更容易瞭解。所以建議對於兩種方法(採用樣式與非採用樣式)的比較,應作更多『舉例說明』,否則無法讓讀者瞭解兩者的差異及其利弊。此外既然是以 Java 來實作,Java 的 collections 已實作 Iterator 功能,建議也可以加以說明。

作者補充說明:

謝謝你的指正,程式這樣寫祗為了說明 Iterator 模式的內涵,的確,Java 已對 collections 實作了 Iterator 的功能,如要補充說明,則如下所示:

import java.util.* ;

public class IteratorExample3 {
    public static void main(String[] args) {
        Vector collection = new Vector(3); // 用 Arrays, List, ArrayList..均可
        collection.add(new Person("Davis"));
        collection.add(new Person("Frank"));
        collection.add(new Person("Jeny"));
        Iterator it = collection.iterator();
        while (it.hasNext()) {
            Person person = (Person)it.next();
            System.out.println("" + person.getName());
        }
    }
}