迭代器模式/Iterator

迭代器模式/Iterator

意圖/適用場景:

迭代器模式的應用在Java語言中司空見慣。

迭代器(Iterator)與聚集(Aggregate)的概念密不可分。聚集是能夠包容一組對象的容器對象,不同種類的聚集組織這些對象的方式是不同的,即擁有不同的結構。

Java語言對聚集有良好的支持,Java聚集對象是實現了共同的java.util.Collection接口的對象,包括Vector、ArrayList、Queue、Stack、Hashtable、Hashmap等等。

迭代器的作用是把聚集中的內容轉換爲線性迭代的形式,這樣做的意圖有兩個:一是把非線性結構轉變爲線性結構的順序結構,方便使用者遍歷;二是把多種不同的聚集匯聚成統一的接口。

這裏描述的迭代器模式與《Java與模式》書中描述稍有不同。即在UML圖中,有意把User與聚集隔離開,這樣做的目的是突顯迭代器在聚集與用戶之間的過渡與轉換作用。而書中原圖則不能表明這一用意。

UML:

迭代器模式/Iterator

參與者:

  1. 抽象迭代器(Iterator):迭代器類的公共接口。
  2. 具體迭代器(ConcreteIterator):實現Iterator接口,並保持迭代過程中的遊標位置。
  3. 聚集(Aggregate):聚集類的公共接口,定義出創建迭代器的接口。
  4. 具體聚集(ConcreteAggregate):實現Aggregate接口,完成創建迭代器的方法。

要點:

迭代器的用法雖然常見,但實現起來卻有很多講究,這裏提及一些所需要考慮的方面,但不作詳細討論:

  1. 正迭代與逆迭代:按照在迭代器中的索引順序,從低索引值到高索引值的迭代過程稱爲正迭代,從高索引值到低索引值的迭代過程稱爲逆迭代。
  2. 寬接口與窄接口:如果一個聚集的接口提供了可以用來修改聚集元素的方法,這個接口就是寬接口;如果 一個聚集的接口沒有提供修改聚集元素的方法,這樣的接口就是窄接口。
  3. 白盒聚集與黑盒聚集:如果一個聚集提供了訪問內部元素的接口,它就稱爲白盒聚集;如果一個聚集沒有向外界提供訪問自身內部元素的接口,就稱爲黑盒聚集。
  4. 外部迭代器與內部迭代器:這一對概念與白/黑盒聚集相關。對於白盒聚集,迭代器的實現可以完全與該聚集的內部結構無關,因爲聚集提供了訪問內部元素的方法,迭代器只需要調用這些方法就可以實現訪問聚集元素的功能,這樣的迭代器稱爲外部迭代器。對於黑盒聚集,因爲聚集沒有提供訪問內部元素的方法,迭代器必須定義爲聚集的一個內部類(內部類仍然可以被外部對象訪問),這樣才能夠訪問聚集的元素,這樣的迭代器稱爲內部迭代器。
  5. 主動迭代器和被動迭代器:這是相對於客戶端來說的。如果客戶端控制迭代的進程(如調用next()方法來移動遊標),這樣的迭代器就是主動迭代器;相反就是被動迭代器。
  6. 靜態迭代器與動態迭代器:這一對概念涉及到同步的問題,稍微擴展一下。
    • 靜態迭代器持有聚集對象的一個快照,一旦產生後這個快昭的內容就不再變化,原聚集的內容可以被修改,對迭代器不會有影響,但是迭代器對象也就反映不現聚集的最新變化。
    • 靜態迭代的好處是安全性和簡單性,它易於實現。但壞處是它需要將原聚集複製一份,對時間和內存資源都有消耗,對於大型的聚集對象來說,成本會比較高。
    • 動態迭代器被產生之後,迭代器仍持有對聚集的引用,因此可以反映出聚集的最新情況。
    • 完整的動態迭代器實現起來比較困難,因爲要考慮同步與迭代器更新的問題。簡化的動態迭代器無法實現迭代器的即時更新,但是應該在聚集元素髮生變化時可以得到通知,這就引出另一個概念:Fail Fast。
  7. Fail Fast:
    • 如果當一個算法開始之後,它的運算環境發生變化,使得算法無法進行必需的調整時,這個算法就應當立即發出故障信號。這就是Fail Fast的含義。
    • 如果聚集對象的元素在一個動態迭代器的迭代過程中變化時,迭代過程會受到影響而無法繼續,這時候,迭代器就應當立即拋出一個異常。這種迭代器就是實現了Fail Fast功能的迭代器。

示例代碼:

Iterator模式在Java類庫java.util.Collection中有很好的示例,這裏不同提供簡化的示例代碼。
只給出一個使用Iterator模式的代碼,用以明示這一模式的作用。
   [java]
// Source code from file:  User.java

package designPatterns.Iterator;

import java.util.*;

public class User {

public Iterator getIteratorFromHashMap() {
HashMap hashMap = new HashMap();
hashMap.put("One", new Integer(1));
hashMap.put("Two", new Integer(2));
hashMap.put("Three", new Integer(3));
return hashMap.keySet().iterator();
}

public Iterator getIteratorFromList() {
List list = new ArrayList();
list.add("One");
list.add("Two");
list.add("Three");
return list.iterator();
}

public static void main(String[] args) {
User user = new User();
Iterator iteratorFromHashMap = user.getIteratorFromHashMap();
Iterator iteratorFromList = user.getIteratorFromList();
while (iteratorFromHashMap.hasNext()){
System.out.println((String)iteratorFromHashMap.next());
}
while (iteratorFromList.hasNext()){
System.out.println((String)iteratorFromList.next());
}
}

}
[/java]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章