結合JDK源碼看設計模式——迭代器模式

来源:https://www.cnblogs.com/Cubemen/archive/2019/04/11/10688624.html
-Advertisement-
Play Games

前言: Iterator翻譯過來就是迭代器的意思。在前面的工廠模式中就介紹過了iterator,不過當時介紹的是方法,現在從Iterator介面的設計來看,似乎又是一種設計模式,下麵我們就來講講迭代器模式到底是怎麼實現的。 一、定義 提供一種方法,順序訪問一個集合對象中的各個元素,而又不暴露該對象的 ...


前言:

  Iterator翻譯過來就是迭代器的意思。在前面的工廠模式中就介紹過了iterator,不過當時介紹的是方法,現在從Iterator介面的設計來看,似乎又是一種設計模式,下麵我們就來講講迭代器模式到底是怎麼實現的。

一、定義

  提供一種方法,順序訪問一個集合對象中的各個元素,而又不暴露該對象的內部表示。(可以理解為遍歷)

二、適用場景

1、訪問一個集合對象的內容而無需暴露它的內部表示

2、為遍歷不同的集合結構提供一個統一的介面

  重要的是對第二點的理解,前面我們在工廠方法中講過iterator是個工廠方法,Iterator是個產品總介面。對於我們需要的是Iterator這個產品,產品的功能是遍歷,我們並不關心這個產品裡面存儲的結構是List還是Map,不同存儲結構的遍歷實現應該交給下麵的不同的工廠去實現。這裡同樣也可以這麼理解。但是,我們今天講的是迭代器模式。工廠模式是創建型,而這個模式是行為型。在這裡我們或許可以先拋開工廠模式,來去理解這個迭代器模式。

三、結合Iterator介面看迭代器

迭代器模式的角色構成

 1、迭代器(Iterator):定義訪問和遍歷元素的介面。

 2、具體迭代器(ConcreteIterator ):具體迭代器,實現了迭代器介面,內部會具體實現如何遍歷當前聚合。

 3、聚合(Aggregate):內部創建相應迭代器介面的方法。

 4、具體聚合(ConcreteAggregate):內部具體有存儲方式以及實現相應迭代器介面,以及一些操作。

  下麵我們來結合源碼來理解上面4個角色具體是什麼樣的:

public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

  上面是迭代器Iterator介面的代碼,定義了一些需要子類實現的方法和預設的方法。在這裡說一下上面兩個default方法都是JDK1.8之後才有的介面新特性,在JDK1.8之前介面中不能有方法實體。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}

  上面是簡化的ArrayList類,因為具體實現迭代器Itr的類在ArrayList中作為內部類存在,這個內部類將介面中的方法做了具體實現,並且是只對ArrayList這個類進行實現的。

public interface List<E> extends Collection<E> {
    Iterator<E> iterator();
}

  上面是簡化的List介面,充當的是聚合介面,可以看見內部創建了相應迭代器介面的方法。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    public Iterator<E> iterator() {
        return new Itr();
    }
}

  上面是簡化的ArrayList類,充當的是具體聚合類角色,在這裡是直接返回了一個具體實現迭代器的類。

public class Test1 {

    public static void main(String[] args) {
      List<Integer> a=new ArrayList<>();
      a.add(1);
      a.add(2);
      a.add(3);
      while(a.iterator().hasNext()){
          System.out.println(a.iterator().next());
      }
    }
}

  這是一個錯誤的測試類,因為我們每調用一次iterator方法都是會new一個Itr對象,也就是裡面的游標會一直重置為0,所以會無限迴圈。下麵才是正確的測試方法

public class Test1 {

    public static void main(String[] args) {
      List<Integer> a=new ArrayList<>();
      a.add(1);
      a.add(2);
      a.add(3);
      Iterator Itr=a.iterator();
      while(Itr.hasNext()){
          System.out.println(Itr.next());
      }
    }
}

四、總結

  平常寫代碼的時候總會有使用iterator。但是如果要我們自己去動手實現一個集合類的會很少,除非是寫框架的時候,大多數我們還是使用為主。當我們需要使用迭代器模式的時候,只需要看上面4個源碼的角色扮演和分析,很快就能寫出自己的迭代器。前面在適用場景的時候我們是用工廠方法模式來去理解Iterator,但學完這個模式之後,以後的Iterator介面下的實現類,你都可以認為是迭代器模式。因為迭代器模式在各種集合對象中用的實在是太廣泛了,所以專門拿這個模式進行源碼解釋。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • CSS3的出現給網站頁面增加了活力,網站增色不少,有這麼小小的一款插件就能做出很多動畫效果。 最重要的是它:簡單易用、輕量級、無需 jQuery......他就是wow.js 地址:https://daneden.github.io/animate.css/ 也可以在這個地方看各種演示 下麵就讓我們 ...
  • 因為是Node伺服器端的,怎樣實現前臺和後臺請求以及回應 URL(由什麼組成的 ),傳輸的內容:表單數據 文件數據 【圖片、壓縮包、各種尾碼文件】 URL的組成 URL由三部分組成: 協議類型 , 主機名 和 路徑及文件名 。通過URL可以指定的主要有以下幾種:http、ftp、gopher、tel ...
  • getter 和 setter: 1、ES5 里,屬性值可以用一個或兩個方法代替,這兩個方法就是 getter 和 setter,它們使用 get 和 set 進行定義而不是通過 function 2、由 getter 和 setter 定義的屬性稱作 “存取器屬性”,它不同於“數據屬性”,數據屬性 ...
  • 又有好長時間沒有寫博客了,今天想起來之前的那篇博客還沒有寫完,然後就開始接著寫,本來想把《高性能JavaScript》這本書的知識都羅列進來的,但是......太多了,哎,還是慢慢來,於是就打算分開來寫。 本人JavaScript水平並不是特別高,也只是把自己閱讀《高性能JavaScript》的部分 ...
  • 現在應用都是前後端分離,這也造成前端在調用介面時出現跨域問題,在控制台會這樣提示 ,如果有類似於此圖的提示,就已經表明你的介面調用出現了跨域問題,此文章是我對於vue跨域其中一種方式的一些經驗,如果錯誤,謝謝諒解!!! 首先對於vue跨域,我們可以用代理:在 config --> index.js里 ...
  • 這是我第一次寫博客,主要是記錄下自己解決問題的過程和知識的總結,如有不對的地方歡迎指出來! 需求:點擊btn,彈出modal顯示圖表(以折現圖為例) 這應該是很基本的需求也是很容易實現的,代碼和效果如下: 代碼解釋:setTem是一個方法,改變modal為true,預設為false ; chart- ...
  • 首先我們來瞭解一下什麼是文檔聲明: 文檔聲明就是文檔告訴游覽器該以什麼樣的標準去解析它。游覽器可以解析的文檔可不止html,還有xhtml,xml...當然在這裡我們並不需要知道xhtml、xml是什麼以及和html的區別,我們只需要知道,游覽器可以解析的文檔不止html ,所以文檔聲明是必須的,為 ...
  • 目的:將多個子系統的認證體系打通,實現一個入口多處使用 共用session最簡單最直接。以session存儲的值為用戶憑證,在用戶信息驗證用戶信息管理與業務應用分離的場景下會遇到單點登錄問題,適用體系簡單,考慮基於redis的session共用方案,將整個系統全局cookiesdomain設置於頂級 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...