在設計程式的過程中,經常有的需求之一,就是希望逐一取得某物件內部的所有資料(或物件),像是取得ArrayList中所有 的資料,或取得HashSet中所有的資料。
例如,您也許會希望設計一個foreach方法,可以將丟給它的物件中的資料逐一取得並顯示在主控台中:
List<String> list = new
ArrayList<String>();
...
foreach(list);
Set<String> set = new HashSet<String>();
....
foreach(set);
...
foreach(list);
Set<String> set = new HashSet<String>();
....
foreach(set);
因為List是有序結構並有索引特性,而Set則為無序不重複的特性,兩者所提供的公開存取方法也不相同,如 何將foreach方法設計的通用是個問題。
無 論是List或Set,都有個iterator()方法可以傳回一個Iterator物件,這個物件會收集List或Set物件內部資料,並有 hasNext()、next()方法可以使用,而實際上,這個方法是繼承自Collection介面(List與Set的父介面),您可以這麼設計 foreach方法:
public static void
foreach(Collection<String> collection) {
Iterator<String> iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
Iterator<String> iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
現在,無論是List或Set,無論真正的實作是ArrayList、LinkedList、HashSet...,都可以使用這個foreach方法來 顯示內部所收集的物件。
這 是Iterator模式的實現,不同的物件內部在組織資料方式並不相同(陣列?鏈結?雜湊?),所提供的公開存取介面也不一樣,為了有一致的方式來逐一取 得物件內部的資料,您可以讓一個Iterator於物件內部進行收集,之後傳回Iterator物件,透過該Iterator來逐一取得物件內部資料。
以Java 的Collection API設計來說,在JDK 1.4時,iterator()方法是定義在Collection介面上,每個Collection的實現類別,都會有iterator()方法,在 JDK5之後,則將iterator()方法定義在Iterable介面上,而Collection介面則繼承了Iterable介面:
由於物件在實作內部資料的組織時方式不盡相同,因此也只有物件本身才知道如何收集內部資料,因此Iterator的實作,通常會是物件的內部類別,外界無 需關心,只要知道如何操作Iterator即可。
由於Iterable介面在JDK5後引進,使得只要是實作Iterable介面的物件,皆可搭配 foreach語法來使用。例如:
import java.util.Iterator;
class IterableString implements Iterable<Character> {
private String original;
public IterableString(String original) {
this.original = original;
}
public Iterator<Character> iterator() {
return new InnerIterator();
}
private class InnerIterator implements Iterator<Character> {
private int index;
public boolean hasNext() {
return index < original.length();
}
public Character next() {
Character c = original.charAt(index);
index++;
return c;
}
public void remove() {}
}
}
public class Main {
public static void main(String[] args) {
foreach(new IterableString("Justin"));
}
public static void foreach(Iterable<Character> iterable) {
Iterator<Character> iterator = iterable.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
以上其實只是為了示範才又寫了一次foreach方法的實現,事實上,JDK5之後引入了foreach語法的支援,您可以直 接這麼撰寫:
for(Character
c : new IterableString("Justin")) {
System.out.println(c);
}
System.out.println(c);
}
Python 在Iterator模式的實現方式,若要結合語法特性,則可透過類別上__iter__與__next__方法的定義。Python的foreach語法 會利用類別上的__iter__方法取得Iterator物件,而後利用所取得的Iterator物件之__next__方法來逐一取得資料,例如:
class NumberGenerator:
class Iterator:
def __init__(self, length):
self.length = length
self.number = -1
def __next__(self):
self.number = self.number + 1
if self.number == self.length:
raise StopIteration
return self.number
def __init__(self, length):
self.length = length
def __iter__(self):
return NumberGenerator.Iterator(self.length)
for n in NumberGenerator(10):
print(n)