迭代器模式
<本模式主要作用在於,對於不同數據結構存儲的數據(如數組,樹,鏈表,散列表等),我們用相同的方式對其進行迭代遍歷,對客服隱藏了底層數據結構的細節,客服只需獲得該類迭代器,既可以通過相同的方式進行迭代>
[ 圖片來源百度百科 ]
以下我們來看具體使用到迭代器的例子。
我們假設我們系統中有兩個類,他們都是用來存東西的,只不過使用的存儲方式不同而已。
class Container1{
private Object[] objs;
public Container1(int cap){
this.objs = new Object[cap];
//開始我們先放點東西進去
for(int i = 0 ; i < cap ; i++)
objs[i] = new Integer(i);
}
public Object[] getObjs(){
return objs;
}
}
Container1 這個容器類 是用數組來存放東西的
class Container2{
private ArrayList<Object> objs;
public Container2(){
this.objs = new ArrayList<Object>();
//開始我們先放點東西進去
for(int i = 0 ; i < 5; i++)
objs.putObj(i , new Integer(i));
}
public ArrayList<Object> getObjs(){
return objs;
}
public Object getObj(int index){
if(objs != null)
return objs.get(index);
return null;
}
public void putObj(int index,Object o){
if(objs != null){
objs.set(index,o);
}
}
}
Container2 容器類 是用ArrayList來存放東西的
接下來我們寫客服端代碼來遍歷他們
class Client{
public static void main(String[] args){
//這個容器類使用的數組來放東西的
Container1 con1 = new Container1(10);
//這個容器類使用的ArrayList來放東西的
Container2 con2 = new Container2();
//現在我們來遍歷容器類中的元素
for(int i = 0 ; i < con1.getObjs().length ; i++)
System.out.println(con1.getObjs()[i]);
for(int i = 0 ; i < con2.getObjs().size(); i++)
System.out.println(con2.getObj(i));
}
}
可以明顯的看到我們遍歷這段代碼很多地方相似,而且這段代碼由於底層數據結構的不同難以修改(因爲數組是通過去下標來訪問的,而ArrayList 則通過get 方法),這樣的代碼有一個缺點在於,如果我們新加入一個容器類,假如他底層是用的樹的數據結構,我們在客服端遍歷他的元素的時候那不又得寫一個for循環,這完全違背了我們所說得設計模式中開閉原則(對擴展打開,對修改關閉)。到這裏我們要解決得問題非常清晰就是得想辦法把這個遍歷過程融爲一體,即我們可以只通過一種方式就可以對不同數據結構得容器類進行迭代。
很容易想到得一個解決方案那就是通過接口(因爲有多態得性質)來規範化迭代行爲。我們先定義一個迭代器接口如下
//該接口規定了兩個方法
interface Iterator{
//判斷容器是否還有下一個元素
boolean hasNext();
//獲取容器下一個元素
Object next();
}
我們直接用容器類來實現該接口?不不不!我們現在還不想改變容器類的代碼(以後可能會改)。在這裏我們將另外寫一個該接口實現類,應該是兩個分別是用來爲迭代這兩個容器的元素。
//數組方式的容器迭代
class Container1Iterator implements Iterator{
Container1 container1;
private int cur = 0;
public Container1Iterator(Container1 container1){
this.container1 = container1;
}
//判斷容器是否還有下一個元素
public boolean hasNext(){
if(container1.getObjects().length <= cur)
return false;
return true;
}
//獲取容器下一個元素
public Object next(){
return container1.getObjects()[cur];
}
}
//以下實現與上面類似此處不累贅
class Container2Iterator implements Iterator{
//.......
}
好既然有了迭代器實現類我們再來看看客服端代碼怎麼修改
class Client{
private void traverse(Iterator iterator){
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
public static void main(String[] args){
//這個容器類使用的數組來放東西的
Container1 con1 = new Container1(10);
//這個容器類使用的ArrayList來放東西的
Container2 con2 = new Container2();
traverse(new Container1Iterator(con1));
traverse(new Container2Iterator(con2));
}
}
完美我們解決了代碼重複的問題,而且當有新的容器類加入時,只要他有Iterator的實現類我們仍然可以通過該方式來進行迭代。到這裏可能有的人還不太滿意,因爲客服端代碼與容器具體類(Container1Iterator , Container1Iterator )是強耦合的,這不是我們喜歡的。
我們來對上面的類來改進以下,我們將兩個容器"融爲一體",通過接口多態的性質。
我們先定義一個公共的接口,該接口規定了一個迭代器創建方法。
interface Iterable{
//該方法用於創建一個迭代器類
Iterator iterator();
}
然後讓容器類去實現他。
class Container1 implements Iterable{
public Iterator iterator(){
return new Container1Iterator(this);
}
//省略其他部分......
}
class Container2 implements Iterable{
public Iterator iterator(){
return new Container2Iterator(this);
}
//省略其他部分......
}
好我們兩個容器類都實現同一個接口,我們接口多態性質終於可以大展身手了。
class Client{
private void traverse(Iterable Iterable){
Iterator iterator = Iterable.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
到這裏我們迭代器模式已經完成。
總結迭代器模式,讓客服端無需關心底層存儲的數據的方式,並且可以通過相同的方式對不同的容器進行迭代。