(參考自設計模式)
在設計程式的過程中,經常有的需求之一,就是希望逐一取得某物件內部的所有資料(或物件),像是取得ArrayList中所有 的資料,或取得HashSet中所有的資料。
由於物件在實作內部資料的組織時方式不盡相同,因此也只有物件本身才知道如何收集內部資料,因此Iterator的實作,通常會是物件的內部類別,外界無 需關心,只要知道如何操作Iterator即可。
以Java 的Collection API設計來說
在JDK 1.4時,iterator()方法是定義在Collection介面上,每個Collection的實現類別,都會有iterator()方法,在 JDK5之後,則將iterator()方法定義在Iterable介面上,而Collection介面則繼承了Iterable介面:
例如,您也許會希望設計一個foreach方法,可以將丟給它的物件中的資料逐一取得並顯示在主控台中:
1 2 3 4 5 6 7 |
List<String> list = new ArrayList<String>(); ... 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方法:
1 2 3 4 5 6 |
public static void foreach(Collection<String> collection) { Iterator<String> iterator = collection.iterator(); while(iterator.hasNext()) { System.out.println(iterator.next()); } } |
這是Iterator模式的實現,不同的物件內部在組織資料方式並不相同(陣列?鏈結?雜湊?),所提供的公開存取介面也不一樣,為了有一致的方式來逐一取 得物件內部的資料,您可以讓一個Iterator於物件內部進行收集,之後傳回Iterator物件,透過該Iterator來逐一取得物件內部資料。
其他語言的一些iterator的範例:
C#
1 2 3 4 5 6 7 8 9 |
// Method that takes an iterable input (possibly an array) // and returns all even numbers. public static IEnumerable<int> GetEven(IEnumerable<int> numbers) { foreach(int i in numbers) { if (i % 2 == 0) yield return i; } } |
C++
1 2 3 4 5 6 7 8 |
template<typename InputIterator> void printall(InputIterator first, InputIterator last) { for(; first != last; ++first) { std::cout << *first << std::endl; } } |
JAVA:
1 2 3 4 |
Iterator iter = list.iterator(); //Iterator<MyType> iter = list.iterator(); in J2SE 5.0 while (iter.hasNext()) System.out.println(iter.next()); |
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
class a implements Iterator { var $keys = array("k1", "k2", "k3"); var $vals = array("v1", "v2", "v3"); var $pos = 0; function current() { return $this->vals[$this->pos]; } function key() { return $this->keys[$this->pos]; } function next() { $this->pos++; } function rewind() { $this->pos = 0; } function valid() { if($this->pos>=count($this->keys)) { return false; } else { return true; } } } $a = new a; foreach($a as $k=>$v) echo "$k:::$v\n"; 執行結果: <blockquote>Feng-Hsu-Pingteki-MacBook-Air:ironman6 fillano$ php 1-4a.php k1:::v1 k2:::v2 k3:::v3</blockquote> |