gembin

          OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

          HBase, Hadoop, ZooKeeper, Cassandra

          Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

          There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

          About Me

           

          深入淺出Java設(shè)計模式之迭代器模式


          迭代這個名詞對于熟悉Java的人來說絕對不陌生。我們常常使用JDK提供的迭代接口進行java collection的遍歷:

          Iterator it = list.iterator();
          while(it.hasNext()){
          //using “it.next();”do some businesss logic
          }

          而這就是關(guān)于迭代器模式應(yīng)用很好的例子。

          二、 定義與結(jié)構(gòu)

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

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

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

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

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

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

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

          3) 容器角色(Container):容器角色負(fù)責(zé)提供創(chuàng)建具體迭代器角色的接口。

          4) 具體容器角色(Concrete Container):具體容器角色實現(xiàn)創(chuàng)建具體迭代器角色的接口——這個具體迭代器角色于該容器的結(jié)構(gòu)相關(guān)。

          迭代器模式的類圖如下:


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

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

          三、 舉例

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

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

          2.在迭代器模式中沒有規(guī)定誰來實現(xiàn)遍歷算法。 好像理所當(dāng)然的要在迭代器角色中實現(xiàn)。因為既便于一個容器上使用不同的遍歷算法,也便于將一種遍歷算法應(yīng)用于不同的容器。但是這樣就破壞掉了容器的封裝 ——容器角色就要公開自己的私有屬性,在java中便意味著向其他類公開了自己的私有屬性。

          那我們把它放到容器角色里來實現(xiàn)好了。這樣迭代器角色就被架空為僅僅存放一個遍歷當(dāng)前位置的功能。但是遍歷算法便和特定的容器緊緊綁在一起了。

          而在Java Collection的應(yīng)用中,提供的具體迭代器角色是定義在容器角色中的內(nèi)部類。這樣便保護了容器的封裝。但是同時容器也提供了遍歷算法接口,你可以擴展自己的迭代器。

          好了,我們來看下Java Collection中的迭代器是怎么實現(xiàn)的吧。

          //迭代器角色,僅僅定義了遍歷接口

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

          //容器角色,這里以List為例。它也僅僅是一個接口,就不羅列出來了
          //具體容器角色,便是實現(xiàn)了List接口的ArrayList等類。為了突出重點這里指羅列和迭代器相關(guān)的內(nèi)容
          //具體迭代器角色,它是以內(nèi)部類的形式出來的。AbstractList是為了將各個具體容器角色的公共部分提取出來而存在的。

          public abstract class AbstractList extends AbstractCollection implements List {
          ……
          //這個便是負(fù)責(zé)創(chuàng)建具體迭代器角色的工廠方法
          public Iterator iterator() {
          return new Itr();
          }

          //作為內(nèi)部類的具體迭代器角色

          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();
          }
          }

          至于迭代器模式的使用。正如引言中所列那樣,客戶程序要先得到具體容器角色,然后再通過具體容器角色得到具體迭代器角色。這樣便可以使用具體迭代器角色來遍歷容器了……

          四、 實現(xiàn)自己的迭代器

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

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

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

          以上兩個問題對于不同結(jié)構(gòu)的容器角色,各不相同,值得考慮。

          五、 適用情況

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

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

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

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

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

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

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

          3) 為遍歷不同的容器結(jié)構(gòu)提供一個統(tǒng)一的接口(多態(tài)迭代)。

          六、 總結(jié)

          迭代器模式在我們的應(yīng)用中很廣泛,希望本文能幫助你理解它。如有不對之處,還請不吝指正。

          posted on 2008-03-11 12:51 gembin 閱讀(520) 評論(0)  編輯  收藏 所屬分類: JavaSE

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(6)

          隨筆分類(440)

          隨筆檔案(378)

          文章檔案(6)

          新聞檔案(1)

          相冊

          收藏夾(9)

          Adobe

          Android

          AS3

          Blog-Links

          Build

          Design Pattern

          Eclipse

          Favorite Links

          Flickr

          Game Dev

          HBase

          Identity Management

          IT resources

          JEE

          Language

          OpenID

          OSGi

          SOA

          Version Control

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          free counters
          主站蜘蛛池模板: 衡阳市| 江安县| 获嘉县| 苏尼特右旗| 盱眙县| 紫云| 农安县| 海伦市| 石城县| 滨州市| 宜丰县| 资阳市| 高密市| 景德镇市| 绥化市| 华宁县| 濉溪县| 三河市| 年辖:市辖区| 鹤山市| 高州市| 长武县| 手游| 绵竹市| 五峰| 安达市| 洮南市| 阿图什市| 南京市| 潼南县| 广汉市| 夏邑县| 当雄县| 锦屏县| 九龙坡区| 四会市| 炎陵县| 资兴市| 湖北省| 东兰县| 临安市|