一 引言 迭代這個名詞對於熟悉Java的人來說絕對不陌生
我們常常使用JDK提供的迭代接口進行java collection的遍歷
Iterator it = erator();
while(it
hasNext()){
//using
it
next();
do some businesss logic
}
而這就是關於迭代器模式應用很好的例子
二 定義與結構 迭代器(Iterator)模式
又叫做游標(Cursor)模式
GOF給出的定義為
提供一種方法訪問一個容器(container)對象中各個元素
而又不需暴露該對象的內部細節
從定義可見
迭代器模式是為容器而生
很明顯
對容器對象的訪問必然涉及到遍歷算法
你可以一股腦的將遍歷方法塞到容器對象中去
或者根本不去提供什麼遍歷算法
讓使用容器的人自己去實現去吧
這兩種情況好像都能夠解決問題
然而在前一種情況
容器承受了過多的功能
它不僅要負責自己
容器
內的元素維護(添加
刪除等等)
而且還要提供遍歷自身的接口
而且由於遍歷狀態保存的問題
不能對同一個容器對象同時進行多個遍歷
第二種方式倒是省事
卻又將容器的內部細節暴露無遺
而迭代器模式的出現
很好的解決了上面兩種情況的弊端
先來看下迭代器模式的真面目吧
迭代器模式由以下角色組成
) 迭代器角色(Iterator)
迭代器角色負責定義訪問和遍歷元素的接口
) 具體迭代器角色(Concrete Iterator)
具體迭代器角色要實現迭代器接口
並要記錄遍歷中的當前位置
) 容器角色(Container)
容器角色負責提供創建具體迭代器角色的接口
) 具體容器角色(Concrete Container)
具體容器角色實現創建具體迭代器角色的接口——這個具體迭代器角色於該容器的結構相關
迭代器模式的類圖如下
從結構上可以看出迭代器模式在客戶與容器之間加入了迭代器角色迭代器角色的加入就可以很好的避免容器內部細節的暴露而且也使得設計符號單一職責原則
注意在迭代器模式中具體迭代器角色和具體容器角色是耦合在一起的——遍歷算法是與容器的內部細節緊密相關的為了使客戶程序從與具體迭代器角色耦合的困境中脫離出來避免具體迭代器角色的更換給客戶程序帶來的修改迭代器模式抽象了具體迭代器角色使得客戶程序更具一般性和重用性這被稱為多態迭代
三 舉例 由於迭代器模式本身的規定比較松散
所以具體實現也就五花八門
我們在此僅舉一例
根本不能將實現方式一一呈現
因此在舉例前
我們先來列舉下迭代器模式的實現方式
.迭代器角色定義了遍歷的接口
但是沒有規定由誰來控制迭代
在Java collection的應用中
是由客戶程序來控制遍歷的進程
被稱為外部迭代器
還有一種實現方式便是由迭代器自身來控制迭代
被稱為內部迭代器
外部迭代器要比內部迭代器靈活
強大
而且內部迭代器在java語言環境中
可用性很弱
.在迭代器模式中沒有規定誰來實現遍歷算法
好像理所當然的要在迭代器角色中實現
因為既便於一個容器上使用不同的遍歷算法
也便於將一種遍歷算法應用於不同的容器
但是這樣就破壞掉了容器的封裝——容器角色就要公開自己的私有屬性
在java中便意味著向其他類公開了自己的私有屬性
那我們把它放到容器角色裡來實現好了
這樣迭代器角色就被架空為僅僅存放一個遍歷當前位置的功能
但是遍歷算法便和特定的容器緊緊綁在一起了
而在Java Collection的應用中
提供的具體迭代器角色是定義在容器角色中的內部類
這樣便保護了容器的封裝
但是同時容器也提供了遍歷算法接口
你可以擴展自己的迭代器
好了
我們來看下Java Collection中的迭代器是怎麼實現的吧
//迭代器角色
僅僅定義了遍歷接口
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
//容器角色
這裡以List為例
它也僅僅是一個接口
就不羅列出來了
//具體容器角色
便是實現了List接口的ArrayList等類
為了突出重點這裡指羅列和迭代器相關的內容
//具體迭代器角色
它是以內部類的形式出來的
AbstractList是為了將各個具體容器角色的公共部分提取出來而存在的
public abstract class AbstractList extends AbstractCollection implements List {
……
//這個便是負責創建具體迭代器角色的工廠方法
public Iterator iterator() {
return new Itr();
}
//作為內部類的具體迭代器角色
private class Itr implements Iterator {
int cursor =
;
int lastRet =
;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public Object next() {
checkForComodification();
try {
Object next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet ==
)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList
this
remove(lastRet);
if (lastRet < cursor)
cursor
;
lastRet =
;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
至於迭代器模式的使用正如引言中所列那樣客戶程序要先得到具體容器角色然後再通過具體容器角色得到具體迭代器角色這樣便可以使用具體迭代器角色來遍歷容器了……
四 實現自己的迭代器
在實現自己的迭代器的時候
一般要操作的容器有支持的接口才可以
而且我們還要注意以下問題
在迭代器遍歷的過程中
通過該迭代器進行容器元素的增減操作是否安全呢?
在容器中存在復合對象的情況
迭代器怎樣才能支持深層遍歷和多種遍歷呢?
以上兩個問題對於不同結構的容器角色
各不相同
值得考慮
五 適用情況 由上面的講述
我們可以看出迭代器模式給容器的應用帶來以下好處
) 支持以不同的方式遍歷一個容器角色
根據實現方式的不同
效果上會有差別
) 簡化了容器的接口
但是在java Collection中為了提高可擴展性
容器還是提供了遍歷的接口
) 對同一個容器對象
可以同時進行多個遍歷
因為遍歷狀態是保存在每一個迭代器對象中的
由此也能得出迭代器模式的適用范圍
) 訪問一個容器對象的內容而無需暴露它的內部表示
) 支持對容器對象的多種遍歷
) 為遍歷不同的容器結構提供一個統一的接口(多態迭代)
六 總結 迭代器模式在我們的應用中很廣泛
希望本文能幫助你理解它
如有不對之處
還請不吝指正
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27339.html