2016/12/16

軟體開發之 Iterator 模式 (疊代器)

(參考自設計模式)
在設計程式的過程中,經常有的需求之一,就是希望逐一取得某物件內部的所有資料(或物件),像是取得ArrayList中所有 的資料,或取得HashSet中所有的資料。

由於物件在實作內部資料的組織時方式不盡相同,因此也只有物件本身才知道如何收集內部資料,因此Iterator的實作,通常會是物件的內部類別,外界無 需關心,只要知道如何操作Iterator即可。

以Java 的Collection API設計來說

在JDK 1.4時,iterator()方法是定義在Collection介面上,每個Collection的實現類別,都會有iterator()方法,在 JDK5之後,則將iterator()方法定義在Iterable介面上,而Collection介面則繼承了Iterable介面:

例如,您也許會希望設計一個foreach方法,可以將丟給它的物件中的資料逐一取得並顯示在主控台中:

List list = new ArrayList();...foreach(list);Set set = new HashSet();....foreach(set);

因為List是有序結構並有索引特性,而Set則為無序不重複的特性,兩者所提供的公開存取方法也不相同,如何將foreach方法設計的通用是個問題。

無論是List或Set,都有個iterator()方法可以傳回一個Iterator物件,這個物件會收集List或Set物件內部資料,並有 hasNext()、next()方法可以使用,而實際上,這個方法是繼承自Collection介面(List與Set的父介面),您可以這麼設計 foreach方法:

public static void foreach(Collection collection) {    Iterator iterator = collection.iterator();    while(iterator.hasNext()) {        System.out.println(iterator.next());    }}

這是Iterator模式的實現,不同的物件內部在組織資料方式並不相同(陣列?鏈結?雜湊?),所提供的公開存取介面也不一樣,為了有一致的方式來逐一取 得物件內部的資料,您可以讓一個Iterator於物件內部進行收集,之後傳回Iterator物件,透過該Iterator來逐一取得物件內部資料。

其他語言的一些iterator的範例:

C#

// Method that takes an iterable input (possibly an array)// and returns all even numbers.public static IEnumerable GetEven(IEnumerable numbers){    foreach(int i in numbers)    {        if (i % 2 == 0) yield return i;    }}

C++

templatevoid printall(InputIterator first, InputIterator last){    for(; first != last; ++first)    {        std::cout << *first << std::endl;    }}

JAVA:

Iterator iter = list.iterator();//Iterator iter = list.iterator();    in J2SE 5.0while (iter.hasNext())    System.out.println(iter.next());

PHP

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";執行結果:
Feng-Hsu-Pingteki-MacBook-Air:ironman6 fillano$ php 1-4a.phpk1:::v1k2:::v2k3:::v3

沒有留言:

張貼留言