隨筆-199  評論-203  文章-11  trackbacks-0

          一、 引言
            迭代這個名詞對于熟悉Java的人來說絕對不陌生。我們常常使用JDK提供的迭代接口進行java collection的遍歷:
          Iterator it = list.iterator();
          while(it.hasNext()){
           //using “it.next();”do some businesss logic
          }
          而這就是關于迭代器模式應用很好的例子。

            二、 定義與結構

            迭代器(Iterator)模式,又叫做游標(Cursor)模式。GOF給出的定義為:提供一種方法訪問一個容器(container)對象中各個元素,而又不需暴露該對象的內部細節。

            從定義可見,迭代器模式是為容器而生。很明顯,對容器對象的訪問必然涉及到遍歷算法。你可以一股腦的將遍歷方法塞到容器對象中去;或者根本不去提供什么遍歷算法,讓使用容器的人自己去實現去吧。這兩種情況好像都能夠解決問題。

            然而在前一種情況,容器承受了過多的功能,它不僅要負責自己“容器”內的元素維護(添加、刪除等等),而且還要提供遍歷自身的接口;而且由于遍歷狀態保存的問題,不能對同一個容器對象同時進行多個遍歷。第二種方式倒是省事,卻又將容器的內部細節暴露無遺。

            而迭代器模式的出現,很好的解決了上面兩種情況的弊端。先來看下迭代器模式的真面目吧。

            迭代器模式由以下角色組成:

            1) 迭代器角色(Iterator):迭代器角色負責定義訪問和遍歷元素的接口。

            2) 具體迭代器角色(Concrete Iterator):具體迭代器角色要實現迭代器接口,并要記錄遍歷中的當前位置。

            3) 容器角色(Container):容器角色負責提供創建具體迭代器角色的接口。

            4) 具體容器角色(Concrete Container):具體容器角色實現創建具體迭代器角色的接口——這個具體迭代器角色于該容器的結構相關。

            迭代器模式的類圖如下:


            從結構上可以看出,迭代器模式在客戶與容器之間加入了迭代器角色。迭代器角色的加入,就可以很好的避免容器內部細節的暴露,而且也使得設計符號“單一職責原則”。

            注意,在迭代器模式中,具體迭代器角色和具體容器角色是耦合在一起的——遍歷算法是與容器的內部細節緊密相關的。為了使客戶程序從與具體迭代器角色耦合的困境中脫離出來,避免具體迭代器角色的更換給客戶程序帶來的修改,迭代器模式抽象了具體迭代器角色,使得客戶程序更具一般性和重用性。這被稱為多態迭代。

            三、 舉例

            由于迭代器模式本身的規定比較松散,所以具體實現也就五花八門。我們在此僅舉一例,根本不能將實現方式一一呈現。因此在舉例前,我們先來列舉下迭代器模式的實現方式。

            1.迭代器角色定義了遍歷的接口,但是沒有規定由誰來控制迭代。在Java collection的應用中,是由客戶程序來控制遍歷的進程,被稱為外部迭代器;還有一種實現方式便是由迭代器自身來控制迭代,被稱為內部迭代器。外部迭代器要比內部迭代器靈活、強大,而且內部迭代器在java語言環境中,可用性很弱。

            2.在迭代器模式中沒有規定誰來實現遍歷算法。好像理所當然的要在迭代器角色中實現。因為既便于一個容器上使用不同的遍歷算法,也便于將一種遍歷算法應用于不同的容器。但是這樣就破壞掉了容器的封裝——容器角色就要公開自己的私有屬性,在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 = 0;
           int lastRet = -1;
           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 == -1)
             throw new IllegalStateException();
             checkForComodification();

            try {
             AbstractList.this.remove(lastRet);
             if (lastRet < cursor)
              cursor--;
             lastRet = -1;
             expectedModCount = modCount;
            } catch(IndexOutOfBoundsException e) {
             throw new ConcurrentModificationException();
            }
           }

           final void checkForComodification() {
            if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
           }
          }
          至于迭代器模式的使用。正如引言中所列那樣,客戶程序要先得到具體容器角色,然后再通過具體容器角色得到具體迭代器角色。這樣便可以使用具體迭代器角色來遍歷容器了……

            四、 實現自己的迭代器

            在實現自己的迭代器的時候,一般要操作的容器有支持的接口才可以。而且我們還要注意以下問題:

            在迭代器遍歷的過程中,通過該迭代器進行容器元素的增減操作是否安全呢?

            在容器中存在復合對象的情況,迭代器怎樣才能支持深層遍歷和多種遍歷呢?

            以上兩個問題對于不同結構的容器角色,各不相同,值得考慮。

            五、 適用情況

            由上面的講述,我們可以看出迭代器模式給容器的應用帶來以下好處:

            1) 支持以不同的方式遍歷一個容器角色。根據實現方式的不同,效果上會有差別。

            2) 簡化了容器的接口。但是在java Collection中為了提高可擴展性,容器還是提供了遍歷的接口。

            3) 對同一個容器對象,可以同時進行多個遍歷。因為遍歷狀態是保存在每一個迭代器對象中的。

            由此也能得出迭代器模式的適用范圍:

            1) 訪問一個容器對象的內容而無需暴露它的內部表示。

            2) 支持對容器對象的多種遍歷。

            3) 為遍歷不同的容器結構提供一個統一的接口(多態迭代)。

          posted on 2009-08-05 20:45 Werther 閱讀(517) 評論(0)  編輯  收藏 所屬分類: 10.Java

          I'm reading...

          Java 60

          Head  First SQL

          寶貝連接


          If you need these books,pls send me emails.
          Email:kunpeng.niu@163.com
          <2009年8月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          303112345

          留言簿(10)

          隨筆分類(178)

          隨筆檔案(208)

          文章檔案(1)

          新聞檔案(6)

          相冊

          1.Java Official Website

          2.Java Study Website

          3.Java Technic Website

          4.Java Video Website

          5.Database Website

          6.Bookshop Website

          7.English Website

          8.Friends Link

          9.Other Web

          積分與排名

          • 積分 - 685679
          • 排名 - 67

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 易门县| 无极县| 内乡县| 榆社县| 东海县| 北票市| 都安| 始兴县| 白河县| 沽源县| 文成县| 乐平市| 余江县| 顺昌县| 樟树市| 绩溪县| SHOW| 大同县| 鸡东县| 珲春市| 平湖市| 申扎县| 郑州市| 寿阳县| 会同县| 广安市| 大石桥市| 亚东县| 仙桃市| 井陉县| 开封县| 工布江达县| 龙陵县| 德惠市| 安徽省| 利津县| 桂阳县| 稻城县| 丁青县| 安新县| 和硕县|