奧推網

選單
財經

迭代器模式 - 行為型

一、迭代器模式的定義

用於遍歷集合物件。“集合物件”也可以叫“容器”“聚合物件”,實際上就是包含一組物件的物件,比如陣列、連結串列、樹、圖、跳錶。迭代器模式將集合物件的遍歷操作從集合類中拆分出來,放到迭代器類中,讓兩者的職責更加單一。

二、集合中的迭代器

一個完整的迭代器模式一般會涉及容器和容器迭代器兩部分內容。為了達到基於介面而非實現程式設計的目的,容器又包含容器介面、容器實現類,迭代器又包含迭代器介面、迭代器實現類。

集合的迭代器。JPG

針對 ArrayList 和 LinkedList 兩個線性容器,設計實現對應的迭代器。按照之前給出的迭代器模式的類圖,定義一個迭代器介面 Iterator,以及針對兩種容器的具體的迭代器實現類 ArrayIterator 和 ListIterator。

// 介面定義方式一public interface Iterator { boolean hasNext(); void next(); E currentItem();}// 介面定義方式二public interface Iterator { boolean hasNext(); E next();}

在第一種定義中,next() 函式用來將遊標後移一位元素,currentItem() 函式用來返回當前遊標指向的元素。在第二種定義中,返回當前元素與後移一位這兩個操作,要放到同一個函式 next() 中完成。

public class ArrayIterator implements Iterator { private int cursor; private ArrayList arrayList; public ArrayIterator(ArrayList arrayList) { this。cursor = 0; this。arrayList = arrayList; } @Override public boolean hasNext() { return cursor != arrayList。size(); //注意這裡,cursor在指向最後一個元素的時候,hasNext()仍舊返回true。 } @Override public void next() { cursor++; } @Override public E currentItem() { if (cursor >= arrayList。size()) { throw new NoSuchElementException(); } return arrayList。get(cursor); }}public class Demo { public static void main(String[] args) { ArrayList names = new ArrayList<>(); names。add(“xzg”); names。add(“wang”); names。add(“zheng”); Iterator iterator = new ArrayIterator(names); while (iterator。hasNext()) { System。out。println(iterator。currentItem()); iterator。next(); } }}

將待遍歷的容器物件,透過建構函式傳遞給迭代器類。實際上,為了封裝迭代器的建立細節,可以在容器中定義一個 iterator() 方法,來建立對應的迭代器。為了能實現基於介面而非實現程式設計,還需要將這個方法定義在 List 介面中。

public interface List { Iterator iterator(); //省略其他介面函式}public class ArrayList implements List { // public Iterator iterator() { return new ArrayIterator(this); } //省略其他程式碼}public class Demo { public static void main(String[] args) { List names = new ArrayList<>(); names。add(“xzg”); names。add(“wang”); names。add(“zheng”); Iterator iterator = names。iterator(); while (iterator。hasNext()) { System。out。println(iterator。currentItem()); iterator。next(); } }}

總結下來就三句話:1。迭代器中需要定義 hasNext()、currentItem()、next() 三個最基本的方法;2。待遍歷的容器物件透過依賴注入傳遞到迭代器類中;3。容器透過 iterator() 方法來建立迭代器。

集合迭代器。JPG

三、迭代器模式的優勢

遍歷集合資料有三種方法:for 迴圈、foreach 迴圈、iterator 迭代器。

List names = new ArrayList<>();names。add(“xzg”);names。add(“wang”);names。add(“zheng”);// 第一種遍歷方式:for迴圈for (int i = 0; i < names。size(); i++) { System。out。print(names。get(i) + “,”);}// 第二種遍歷方式:foreach迴圈for (String name : names) { System。out。print(name + “,”)}// 第三種遍歷方式:迭代器遍歷Iterator iterator = names。iterator();while (iterator。hasNext()) { System。out。print(iterator。next() + “,”);//Java中的迭代器介面是第二種定義方式,next()既移動遊標又返回資料}

for 迴圈遍歷方式比起迭代器遍歷方式,程式碼看起來更加簡潔。為什麼還要用迭代器來遍歷容器呢?為什麼還要給容器設計對應的迭代器呢?

1。類似陣列和連結串列這樣的資料結構,遍歷方式比較簡單,直接使用 for 迴圈來遍歷就足夠了。但是對於複雜的資料結構(比如樹、圖)來說,有各種複雜的遍歷方式。比如,樹有前中後序、按層遍歷,圖有深度優先、廣度優先遍歷等等。因此,可以將遍歷操作拆分到迭代器類中,例如,針對圖的遍歷,可以定義 DFSIterator、BFSIterator 兩個迭代器類。

2。將遊標指向的當前位置等資訊,儲存在迭代器類中,每個迭代器獨享遊標資訊。可以建立多個不同的迭代器,同時對同一個容器進行遍歷而互不影響。

3。容器和迭代器都提供了抽象的介面,便於基於介面而非具體的實現程式設計。當需要切換新的遍歷演算法的時候,例如從前往後遍歷連結串列切換成從後往前遍歷連結串列,客戶端程式碼只需要將迭代器類從 LinkedIterator 切換為 ReversedLinkedIterator 即可,其他程式碼都不需要修改