迭代器模式-統一集合的遍歷方式
公號:碼農充電站pro
主頁://codeshellme.github.io
今天來介紹迭代器模式(Iterator Design Pattern
),它還有另一個名字,叫作游標模式(Cursor Design Pattern
)。
1,遍歷集合元素
現在的高級語言(比如 C++
,Java
,Python
等)都支援很多種集合(比如 List
,Map
,Set
等),用於存儲對象。
同時這些高級語言也都原生支援了迭代器,這使得遍歷集合變得非常簡單。
下面我們來看下,如果不使用迭代器,如何遍歷集合。
以 Java ArrayList
為例,創建 list
,並加入 5 個元素:
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
用 for 循環遍歷 list
:
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
如果不用迭代器,只能使用 get
方法,將集合中的元素一個個取出。
如果使用迭代器遍曆元素,就可以像下面這樣:
Iterator<Integer> i = list.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
先用 iterator
方法返回迭代器,再用 hasNext
方法查看迭代器中是否還有元素,如果有元素則用 next
方法取出元素。
更簡單的方式是使用 forEeah
循環:
for (Object i: list) {
System.out.println(i);
}
forEach 循環(對迭代器的一種包裝)是 Java 5 中引入的遍歷集合的方式,這種方式不再需要獲取迭代器,甚至不需要知道所遍歷的是哪種數據結構,也不需知道其中存儲的是什麼類型的數據。
Java 集合框架與迭代器
Java 中的 Set
,List
,Queue
都實現了 Collection
介面,該介面中的 iterator
方法返回一個迭代器,用於遍歷集合中的元素。
這使得所有的 Collection
對象的遍歷都變得非常簡單,使用 forEach
循環即可:
for (Object o: collection) {
// 遍曆元素
}
2,迭代器模式
迭代器模式提供了一種方法,用於遍歷集合對象中的元素,而又不暴露其內部的細節。
一般的迭代器都要實現一個迭代器介面,該介面至少包含兩個方法,即 hasNext
和 next
:
public interface Iterator {
boolean hasNext();
Object next();
}
hasNext
方法用於查看集合中是否還有下一個元素;next
方法用於返回集合中的下一個元素,並移動指向元素的游標。
Java 中的 Iterator 介面中還有一個
remove
方法,其實這個方法的必要性並不大,所以它的默認實現是拋出UnsupportedOperationException
異常。因此,對於remove
方法,不需要給予太多的關注。
這使得每個集合中的元素的訪問方式都是統一的。
一個完整的迭代器模式一般會包含集合與迭代器兩部分,為了達到基於介面而非實現編程的原則,還抽象出了兩個介面,其類圖如下:
Collection 中的 iterator
方法用於返回當前對象的迭代器,從而遍歷集合中的元素。
迭代器模式將集合對象的遍歷操作從集合類中拆分出來,放到迭代器類中,使得兩者的職責更加單一。
這其實用到了單一職責原則:一個類應該只有一個引起變化的原因。
3,迭代器不支援增刪
迭代器的目的是為了方便元素的遍歷,而如果在遍歷的過程中增刪元素,則會導致元素重複遍歷或者遍歷不到。
下面來看下這種錯誤是如何產生的。
假設一個列表中有 a
,b
,c
,d
四個元素,我們從前往後遍歷。剛開始時,游標 cursor
指向 a
:
當遍歷到 b
時,cursor
指向 b
:
遍歷時刪除元素
如果此時將 a
元素刪除,那麼所有其它元素都會前移一個位置:
從而,這時的游標就會指向 c
,這就會導致 b
沒有被遍歷到。
遍歷時增加元素
如果在遍歷到 b
的時候,在表頭增加一個元素 x
,那麼所有的元素都會後移一個位置:
從而,這時的游標依然是指向 a
,這就會導致 a
被重複遍歷了。
因此,在使用迭代器遍曆元素的時候都會禁止增刪元素。
Java 如何禁止增刪元素
為了禁止在遍歷時增刪元素,Java 的做法是,在遍曆元素時會進行 checkForXXX
操作,目的是檢查是否有元素增刪,如果有增刪的情況,則拋出異常。
4,總結
迭代器模式是為了方便元素的遍歷,它統一了集合的遍歷方式。它將元素的遍歷操作從集合中拆分出來,從而使得兩者得以解耦。
大部分高級語言都原生支援迭代器,這使得開發人員可以專註於業務實現,而不用過多的關心底層實現。
如果在迭代器的遍歷過程中增刪元素,則會導致元素的遍歷發生錯誤,因此迭代器中一般不支援增刪元素。
(本節完。)
推薦閱讀:
歡迎關注作者公眾號,獲取更多技術乾貨。