結合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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...