迭代器模式-統一集合的遍歷方式

公號:碼農充電站pro
主頁://codeshellme.github.io

今天來介紹迭代器模式Iterator Design Pattern),它還有另一個名字,叫作游標模式Cursor Design Pattern)。

1,遍歷集合元素

現在的高級語言(比如 C++JavaPython 等)都支援很多種集合(比如 ListMapSet 等),用於存儲對象。

同時這些高級語言也都原生支援了迭代器,這使得遍歷集合變得非常簡單。

下面我們來看下,如果不使用迭代器,如何遍歷集合。

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 中的 SetListQueue 都實現了 Collection 介面,該介面中的 iterator 方法返回一個迭代器,用於遍歷集合中的元素。

這使得所有的 Collection 對象的遍歷都變得非常簡單,使用 forEach 循環即可:

for (Object o: collection) {
    // 遍曆元素
}

2,迭代器模式

迭代器模式提供了一種方法,用於遍歷集合對象中的元素,而又不暴露其內部的細節

一般的迭代器都要實現一個迭代器介面,該介面至少包含兩個方法,即 hasNextnext

public interface Iterator {
    boolean hasNext();
    Object next();
}

hasNext 方法用於查看集合中是否還有下一個元素;next 方法用於返回集合中的下一個元素,並移動指向元素的游標。

Java 中的 Iterator 介面中還有一個 remove 方法,其實這個方法的必要性並不大,所以它的默認實現是拋出 UnsupportedOperationException 異常。因此,對於 remove 方法,不需要給予太多的關注。

這使得每個集合中的元素的訪問方式都是統一的。

一個完整的迭代器模式一般會包含集合迭代器兩部分,為了達到基於介面而非實現編程的原則,還抽象出了兩個介面,其類圖如下:

在這裡插入圖片描述

Collection 中的 iterator 方法用於返回當前對象的迭代器,從而遍歷集合中的元素。

迭代器模式將集合對象的遍歷操作從集合類中拆分出來,放到迭代器類中,使得兩者的職責更加單一。

這其實用到了單一職責原則:一個類應該只有一個引起變化的原因。

3,迭代器不支援增刪

迭代器的目的是為了方便元素的遍歷,而如果在遍歷的過程中增刪元素,則會導致元素重複遍歷或者遍歷不到

下面來看下這種錯誤是如何產生的。

假設一個列表中有 abcd 四個元素,我們從前往後遍歷。剛開始時,游標 cursor 指向 a

在這裡插入圖片描述

當遍歷到 b 時,cursor 指向 b

在這裡插入圖片描述

遍歷時刪除元素

如果此時將 a 元素刪除,那麼所有其它元素都會前移一個位置:

在這裡插入圖片描述

從而,這時的游標就會指向 c,這就會導致 b 沒有被遍歷到。

遍歷時增加元素

如果在遍歷到 b 的時候,在表頭增加一個元素 x,那麼所有的元素都會後移一個位置:

在這裡插入圖片描述

從而,這時的游標依然是指向 a,這就會導致 a 被重複遍歷了。

因此,在使用迭代器遍曆元素的時候都會禁止增刪元素。

Java 如何禁止增刪元素

為了禁止在遍歷時增刪元素,Java 的做法是,在遍曆元素時會進行 checkForXXX 操作,目的是檢查是否有元素增刪,如果有增刪的情況,則拋出異常。

4,總結

迭代器模式是為了方便元素的遍歷,它統一了集合的遍歷方式。它將元素的遍歷操作從集合中拆分出來,從而使得兩者得以解耦。

大部分高級語言都原生支援迭代器,這使得開發人員可以專註於業務實現,而不用過多的關心底層實現。

如果在迭代器的遍歷過程中增刪元素,則會導致元素的遍歷發生錯誤,因此迭代器中一般不支援增刪元素。

(本節完。)


推薦閱讀:

裝飾者模式-動態的包裝原有對象的行為

命令模式-將請求封裝成對象

適配器模式-讓不兼容的介面得以適配

外觀模式-簡化子系統的複雜性

模板方法模式-封裝一套演算法流程


歡迎關注作者公眾號,獲取更多技術乾貨。

碼農充電站pro