迭代器模式:集合遍歷的統一之道

引言:集合遍歷的演進之路

在軟件開發中,集合遍歷是我們每天都要面對的基礎操作。從最初的數組索引遍歷到現代的流式處理,我們經歷了:

原始索引遍歷
迭代器模式
內部迭代器
Stream API

然而,即使有了高級API,迭代器模式仍然是理解集合遍歷本質的關鍵。它提供了一種統一的方式訪問各種聚合對象中的元素,而無需暴露底層表示。本文將深入解析迭代器模式的原理、實現及高級應用場景。


一、模式定義與核心思想

1.1 官方定義

迭代器模式 (Iterator Pattern):提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內部表示。

1.2 設計哲學

客戶端
迭代器接口
具體迭代器
聚合接口
具體聚合

核心原則

  1. 單一職責:將遍歷邏輯與集合實現分離
  2. 開閉原則:新增集合類型不影響遍歷代碼
  3. 統一接口:為不同集合提供一致的遍歷方式

二、模式結構解析

2.1 UML類圖

創建
訪問
?interface?
Iterator
+hasNext() : boolean
+next() : Object
+remove() : void
ConcreteIterator
-collection: Collection
-cursor: int
+hasNext()
+next()
+remove()
?interface?
Aggregate
+createIterator() : Iterator
ConcreteAggregate
-elements: Object[]
+createIterator()

2.2 關鍵角色

角色職責Java集合示例
Iterator定義遍歷接口java.util.Iterator
ConcreteIterator實現具體遍歷邏輯ArrayList.Itr
Aggregate定義創建迭代器接口java.lang.Iterable
ConcreteAggregate實現集合創建迭代器ArrayList

三、代碼實戰:自定義集合實現

3.1 場景描述

實現一個支持多種遍歷方式的二維矩陣:

  • 行優先遍歷(從左到右,從上到下)
  • 列優先遍歷(從上到下,從左到右)
  • 對角線遍歷

3.2 核心實現

// 迭代器接口
public interface MatrixIterator<T> {boolean hasNext();T next();
}// 矩陣接口
public interface Matrix<T> {int getRows();int getColumns();T get(int row, int col);MatrixIterator<T> rowMajorIterator();MatrixIterator<T> columnMajorIterator();MatrixIterator<T> diagonalIterator();
}// 具體矩陣實現
public class ArrayMatrix<T> implements Matrix<T> {private final T[][] data;public ArrayMatrix(T[][] data) {this.data = data;}@Overridepublic int getRows() {return data.length;}@Overridepublic int getColumns() {return data[0].length;}@Overridepublic T get(int row, int col) {return data[row][col];}// 行優先迭代器@Overridepublic MatrixIterator<T> rowMajorIterator() {return new RowMajorIterator();}// 列優先迭代器@Overridepublic MatrixIterator<T> columnMajorIterator() {return new ColumnMajorIterator();}// 對角線迭代器@Overridepublic MatrixIterator<T> diagonalIterator() {return new DiagonalIterator();}// 行優先迭代器實現private class RowMajorIterator implements MatrixIterator<T> {private int row = 0;private int col = 0;@Overridepublic boolean hasNext() {return row < getRows() && col < getColumns();}@Overridepublic T next() {if (!hasNext()) throw new NoSuchElementException();T element = get(row, col);col++;if (col >= getColumns()) {col = 0;row++;}return element;}}// 列優先迭代器實現private class ColumnMajorIterator implements MatrixIterator<T> {private int row = 0;private int col = 0;@Overridepublic boolean hasNext() {return col < getColumns() && row < getRows();}@Overridepublic T next() {if (!hasNext()) throw new NoSuchElementException();T element = get(row, col);row++;if (row >= getRows()) {row = 0;col++;}return element;}}// 對角線迭代器實現private class DiagonalIterator implements MatrixIterator<T> {private int diag = 0;private int pos = 0;@Overridepublic boolean hasNext() {return diag < (getRows() + getColumns() - 1);}@Overridepublic T next() {if (!hasNext()) throw new NoSuchElementException();int row, col;if (diag < getRows()) {row = diag - pos;col = pos;} else {row = getRows() - 1 - pos;col = diag - getRows() + 1 + pos;}T element = get(row, col);pos++;if (pos > diag || (diag >= getRows() && pos >= getRows() + getColumns() - diag - 1)) {diag++;pos = 0;}return element;}}
}

3.3 客戶端使用

public class MatrixClient {public static void main(String[] args) {Integer[][] matrixData = {{1, 2, 3},{4, 5, 6},{7, 8, 9}};Matrix<Integer> matrix = new ArrayMatrix<>(matrixData);System.out.println("行優先遍歷:");printIterator(matrix.rowMajorIterator());System.out.println("\n列優先遍歷:");printIterator(matrix.columnMajorIterator());System.out.println("\n對角線遍歷:");printIterator(matrix.diagonalIterator());}private static void printIterator(MatrixIterator<?> iterator) {while (iterator.hasNext()) {System.out.print(iterator.next() + " ");}System.out.println();}
}/* 輸出:
行優先遍歷:
1 2 3 4 5 6 7 8 9 列優先遍歷:
1 4 7 2 5 8 3 6 9 對角線遍歷:
1 2 4 3 5 7 6 8 9 
*/

3.4 遍歷過程可視化

1-2-3-4-5-6-7-8-9
1-4-7-2-5-8-3-6-9
1-2-4-3-5-7-6-8-9
行優先遍歷
順序訪問
列優先遍歷
跨行訪問
對角線遍歷
斜向訪問

四、迭代器模式進階技巧

4.1 線程安全迭代器

public class SafeIterator<T> implements Iterator<T> {private final Object lock = new Object();private final Iterator<T> delegate;public SafeIterator(Iterator<T> delegate) {this.delegate = delegate;}@Overridepublic boolean hasNext() {synchronized (lock) {return delegate.hasNext();}}@Overridepublic T next() {synchronized (lock) {return delegate.next();}}@Overridepublic void remove() {synchronized (lock) {delegate.remove();}}
}

4.2 過濾迭代器

public class FilterIterator<T> implements Iterator<T> {private final Iterator<T> source;private final Predicate<T> filter;private T nextElement;private boolean hasNext;public FilterIterator(Iterator<T> source, Predicate<T> filter) {this.source = source;this.filter = filter;findNext();}private void findNext() {while (source.hasNext()) {T candidate = source.next();if (filter.test(candidate)) {nextElement = candidate;hasNext = true;return;}}hasNext = false;}@Overridepublic boolean hasNext() {return hasNext;}@Overridepublic T next() {if (!hasNext) throw new NoSuchElementException();T result = nextElement;findNext();return result;}
}// 使用示例
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Iterator<Integer> evenIterator = new FilterIterator<>(numbers.iterator(), n -> n % 2 == 0
);

4.3 分頁迭代器

public class PagingIterator<T> implements Iterator<List<T>> {private final Iterator<T> source;private final int pageSize;public PagingIterator(Iterator<T> source, int pageSize) {this.source = source;this.pageSize = pageSize;}@Overridepublic boolean hasNext() {return source.hasNext();}@Overridepublic List<T> next() {if (!hasNext()) throw new NoSuchElementException();List<T> page = new ArrayList<>(pageSize);for (int i = 0; i < pageSize && source.hasNext(); i++) {page.add(source.next());}return page;}
}// 使用示例
List<Integer> bigList = IntStream.range(0, 1000).boxed().collect(Collectors.toList());
Iterator<List<Integer>> pageIterator = new PagingIterator<>(bigList.iterator(), 100);while (pageIterator.hasNext()) {List<Integer> page = pageIterator.next();processPage(page);
}

五、應用場景分析

5.1 典型應用場景

場景迭代器應用優勢
集合框架Java集合遍歷統一訪問接口
文件系統目錄遍歷隱藏文件系統差異
數據庫結果集遍歷抽象數據庫訪問
樹形結構多種遍歷算法解耦結構與遍歷
流處理數據管道支持鏈式操作

5.2 使用時機判斷

當出現以下情況時考慮迭代器模式:

  1. 需要統一訪問不同聚合結構
  2. 需要支持多種遍歷方式
  3. 需要隱藏聚合的內部結構
  4. 需要為聚合提供遍歷接口

5.3 不適用場景

  1. 簡單數組或列表遍歷
  2. 性能極度敏感的場景
  3. 只需要順序訪問的不可變集合

六、模式優劣辯證

6.1 優勢 ?

35% 25% 20% 15% 5% 迭代器模式優勢 解耦集合與遍歷 多種遍歷支持 統一訪問接口 延遲加載支持 開閉原則支持

6.2 劣勢 ?

  1. 性能開銷:比直接索引訪問慢
  2. 復雜性增加:簡單場景過度設計
  3. 并發修改問題:迭代中修改集合導致異常
  4. 單向遍歷限制:標準迭代器只支持單向移動

七、與其他模式的關系

7.1 迭代器模式 vs 訪問者模式

遍歷元素
對元素執行操作
迭代器模式
訪問者模式
  • 協同關系:迭代器負責遍歷,訪問者負責操作
  • 區別
    • 迭代器:關注元素訪問順序
    • 訪問者:關注元素操作邏輯

7.2 迭代器模式 vs 組合模式

維度迭代器模式組合模式
目的遍歷元素構建樹形結構
關注點訪問順序結構組織
典型配合常遍歷組合結構常提供迭代器

八、在Java集合框架中的應用

8.1 迭代器接口演進

Enumeration
Iterator
ListIterator
Spliterator

8.2 ArrayList迭代器實現

// ArrayList內部迭代器
private class Itr implements Iterator<E> {int cursor;       // 下一個元素索引int lastRet = -1; // 最后返回的元素索引int expectedModCount = modCount; // 并發修改檢查public boolean hasNext() {return cursor != size;}public E next() {checkForComodification();int i = cursor;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();}}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
}

8.3 Java 8 Spliterator

public interface Spliterator<T> {boolean tryAdvance(Consumer<? super T> action);Spliterator<T> trySplit();long estimateSize();int characteristics();
}// 使用示例
List<String> list = Arrays.asList("a", "b", "c");
Spliterator<String> spliterator = list.spliterator();// 順序處理
spliterator.forEachRemaining(System.out::println);// 并行處理
spliterator.trySplit().forEachRemaining(System.out::println);

九、最佳實踐指南

9.1 設計建議

  1. 使用Iterator而不是直接訪問

    // 好
    for (Iterator<Item> it = collection.iterator(); it.hasNext(); ) {Item item = it.next();// ...
    }// 更好 (Java 5+)
    for (Item item : collection) {// ...
    }
    
  2. 支持fail-fast機制

    public class SafeIterable<T> implements Iterable<T> {private final List<T> data = new ArrayList<>();private volatile int modCount = 0;@Overridepublic Iterator<T> iterator() {return new SafeIterator<>(data.iterator(), modCount);}private class SafeIterator implements Iterator<T> {private final Iterator<T> delegate;private final int expectedModCount;public SafeIterator(Iterator<T> delegate, int modCount) {this.delegate = delegate;this.expectedModCount = modCount;}private void checkModification() {if (modCount != expectedModCount) {throw new ConcurrentModificationException();}}@Overridepublic boolean hasNext() {checkModification();return delegate.hasNext();}// next() 和 remove() 類似}
    }
    

9.2 性能優化

  1. 隨機訪問優化

    public class RandomAccessIterator<T> implements Iterator<T> {private final RandomAccess randomAccess;private final int size;private int index = 0;public RandomAccessIterator(List<T> list) {if (!(list instanceof RandomAccess)) {throw new IllegalArgumentException("List must support random access");}this.randomAccess = (RandomAccess) list;this.size = list.size();}@Overridepublic boolean hasNext() {return index < size;}@Overridepublic T next() {return ((List<T>) randomAccess).get(index++);}
    }
    
  2. 延遲加載迭代器

    public class LazyIterator<T> implements Iterator<T> {private final Supplier<T> supplier;private T next;public LazyIterator(Supplier<T> supplier) {this.supplier = supplier;advance();}private void advance() {next = supplier.get();}@Overridepublic boolean hasNext() {return next != null;}@Overridepublic T next() {if (next == null) throw new NoSuchElementException();T result = next;advance();return result;}
    }
    

9.3 遍歷策略對比

策略時間復雜度空間復雜度適用場景
順序迭代O(n)O(1)鏈表、文件流
隨機訪問O(1)O(1)數組、ArrayList
分頁迭代O(n)O(pageSize)大數據集
并行迭代O(n/p)多核處理器

十、總結:迭代器模式的核心價值

迭代器模式通過解耦遍歷實現了:

獨立演化
獨立演化
簡化客戶端
集合實現
系統靈活性
遍歷算法
統一接口
代碼可維護性

設計啟示
將遍歷視為獨立于集合結構的操作,讓集合專注存儲,迭代器專注訪問

正如《設計模式》作者GoF所強調:

“迭代器模式提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露其內部的表示”


擴展思考

  1. 如何在分布式系統中實現迭代器?
  2. 迭代器模式如何與響應式編程結合?
  3. 如何設計支持雙向遍歷的迭代器?

附錄:Java迭代器發展史

版本特性代表類/接口
JDK 1.0基本枚舉Enumeration
JDK 1.2標準迭代器Iterator
JDK 1.5增強for循環Iterable
JDK 1.5雙向迭代ListIterator
JDK 8并行迭代Spliterator
JDK 8流式迭代Stream

迭代器模式是構建靈活、可擴展集合框架的基石,其設計思想深刻影響了現代編程語言的數據處理范式

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/85349.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/85349.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/85349.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Security OAuth2 組件

我們來系統地講解一下 Spring Security OAuth2 這個強大的組件。我會從概念、作用、核心組件&#xff0c;以及實際應用場景來為你剖析。 1. 什么是 Spring Security OAuth2&#xff1f; 簡單來說&#xff0c;Spring Security OAuth2 是 Spring Security 框架的一個模塊&#…

Redis的持久化功能

Redis的持久化功能能夠將內存中的數據保存到磁盤&#xff0c;從而在重啟后恢復數據。下面為你詳細介紹Redis的兩種主要持久化方式及其配置方法。 RDB&#xff08;Redis Database&#xff09;持久化 RDB持久化是通過生成某個時間點的數據集快照來實現的。它具有高性能的特點&a…

Chrome 將成為下一個 IE6

最近在技術圈刷到一個帖子&#xff0c;說&#xff1a;“Chrome 就快變成新的 IE6 了。” 乍一看有點危言聳聽&#xff0c;但你一細品&#xff0c;發現還真挺像回事。 想當年&#xff1a;IE6 是怎么垮的&#xff1f; IE6 當年多風光&#xff1f;全球市場份額一度超過 90%&#…

Redis 配置文件詳解redis.conf 從入門到實戰

一、redis.conf 是什么&#xff1f; Redis 的配置文件&#xff08;默認命名為 redis.conf&#xff0c;Redis 8.0 之后改為 redis-full.conf&#xff09;控制著服務運行的各項參數。該文件采用以下結構&#xff1a; 指令名 參數1 參數2 ... 參數N例如&#xff1a; replicaof …

autoware docker的安裝

前言 官方的安裝說明&#xff1a; 官方的安裝說明 安裝前&#xff0c;請確認安裝的硬件&#xff1a; CPU with 8 cores16GB RAM[Optional] NVIDIA GPU (4GB RAM) 滿足需求 1. 安裝軟件依賴 這一步主要是安裝三個軟件&#xff1a; DockerNVIDIA Container Toolkit (pref…

AWS 解決方案深度剖析:Amazon QLDB — 構建可信賴、不可變的數據審計基石

導言&#xff1a;數據可信的挑戰 在現代應用開發中&#xff0c;尤其是在金融、供應鏈、身份認證、政府事務、醫療記錄管理等領域&#xff0c;數據完整性和歷史追溯性至關重要。我們常常面臨以下挑戰&#xff1a; 審計困難&#xff1a; 如何證明數據從誕生至今未被篡改&#xf…

Leetcode-?1358. 包含所有三種字符的子字符串數目?

Problem: 1358. 包含所有三種字符的子字符串數目 思路 滑動窗口 解題過程 滑動窗口&#xff1a;使用左右指針 l 和 r 維護一個窗口&#xff0c;窗口內字符的頻次由 cnt 記錄。 右指針擴展&#xff1a;右指針 r 不斷右移&#xff0c;將字符加入窗口并更新頻率。 左指針收縮&a…

iTunes 無法備份 iPhone:10 種解決方法

Apple 設備是移動設備市場上最先進的產品之一&#xff0c;但有些人遇到過 iTunes 因出現錯誤而無法備份 iPhone 的情況。iTunes 拒絕備份 iPhone 時&#xff0c;可能會令人非常沮喪。不過&#xff0c;幸運的是&#xff0c;我們有 10 種有效的方法可以解決這個問題。您可以按照以…

Unity 接入抖音小游戲一

目錄 一、搭建小游戲環境 二、接入抖音SDK 1.初始化 2.登錄 3.分享 4.添加到桌面 5.側邊欄功能 6. 接入流量主 三、完整代碼 下一篇傳送門 Unity 接入抖音小游戲二 -CSDN博客 一、搭建小游戲環境 我這邊因為沒有下載其他版本的Unity所以就先用2022.3.57f1了 大家還是下載…

Node.js 項目啟動命令全面指南:從入門到精通(術語版)

文章目錄 Node.js 項目啟動命令全面指南&#xff1a;從入門到精通一、核心啟動命令深度解析1. 基礎命令結構與執行機制2. 參數傳遞機制詳解 二、常用命令分類詳解1. 運行環境命令對比2. 質量保障命令詳解3. 構建部署全流程 三、高級配置實戰技巧1. 環境變量管理進階2. 命令組合…

創意風格行業PPT模版分享

極簡主題PPT模版&#xff0c;設計類PPT模版&#xff0c;快樂童年成長PPT模版&#xff0c;教育機構通用PPT模版&#xff0c;創意風格行業PPT模版 創意風格行業PPT模版分享&#xff1a;https://pan.quark.cn/s/3bac52e09479

Java + Spring Boot + MyBatis 枚舉變量傳遞給XML映射文件做判斷

枚舉定義 ReagentStatus.java package com.weiyu.utils.enums;import lombok.Getter;/*** 試劑狀態枚舉*/ Getter public enum ReagentStatus {// 常規REGULAR,// 少庫存LESS_INVENTORY,// 零庫存ZERO_INVENTORY,// 將過期WILL_EXPIRE,// 已過期EXPIRED,// 已注銷LOGGED,// 全…

華為云Flexus+DeepSeek征文 | 華為云CCE容器高可用部署Dify高可用版實測:從0到1的高可靠應用實踐

引言 隨著大語言模型&#xff08;LLM&#xff09;技術的爆發&#xff0c;如何快速構建具備高可用、彈性擴展能力的AI應用開發平臺&#xff0c;成為企業數字化轉型的關鍵命題。華為云依托其云原生基礎設施&#xff0c;推出CCE容器高可用版Dify部署方案&#xff0c;通過“一鍵部…

c++_cout的理解和使用

問題引入 cout << (uf.is_same_set(x, y)) ? Y : N<<endl; 請問大家&#xff0c;這條語句對嗎&#xff1f;&#xff08;這里的uf.is_same_set(x, y)是一個自定義函數&#xff0c;返回bool值&#xff1b;所以不是問題的關鍵&#xff09;》 答案是這條語句報錯了…

山東大學項目實訓-創新實訓-法律文書專家系統-項目報告(八)

項目實訓博客 : 項目后端架構 , 項目的四端交互(前端 ,后端 ,模型端 ,數據庫)的開發和維護 , 項目功能總覽 作為項目的后端和前端交互功能主要開發者,我需要對項目的四端交互進行開發和維護. 總覽: 整體項目結構如圖所示: 前后端的交互: 前端封裝了request.js : 方便前端…

12.8Java Swing 中的MVC

在 Java Swing 中&#xff0c;MVC 模式被廣泛應用。例如&#xff0c;JTable、JList 等組件都采用了這種模式。通常&#xff1a; 模型&#xff1a;實現特定的 Swing 模型接口&#xff08;如 TableModel、ListModel&#xff09;。視圖&#xff1a;是 Swing 組件本身&#xff08;…

DDS(Data Distribution Service)

DDS&#xff08;Data Distribution Service&#xff09;是一種以數據為中心的發布/訂閱&#xff08;DCPS&#xff09;通信中間件協議棧標準&#xff08;由OMG組織維護&#xff09;。它專為高性能、可預測、實時、可靠的分布式系統設計&#xff0c;廣泛應用于國防、航空航天、工…

python爬蟲關于多進程,多線程,協程的使用

簡介&#xff1a; python其實沒有真正意義的多線程&#xff0c;因為有GIL鎖存在&#xff0c;但是python3.13去掉GIL鎖&#xff0c;有兩個版本&#xff0c;python3.13t和python3.13&#xff0c;python3.13去掉GIL鎖相當于python底層大規模改變&#xff0c;肯定會影響一些庫的使…

java 設計模式_行為型_23狀態模式

23.狀態模式 Java中的狀態設計模式是一種軟件設計模式&#xff0c;當對象的內部狀態更改時&#xff0c;該模式允許對象更改其行為。狀態設計模式通常用于以下情況&#xff1a;對象取決于其狀態&#xff0c;并且在運行期間必須根據其內部狀態更改其行為。狀態設計模式是許多行為…

Flink CDC MySQL 時區相差 8 小時問題優雅解決方式

Flink CDC MySQL 時區相差 8 小時問題解析 代碼運行環境 Flink 1.15 + FlinkCDC 2.4.0 + jdk1.8 +springboot 2.31、原因分析 Flink CDC 底層使用 Debezium 連接器來捕獲 MySQL 的數據變更,而 Debezium 在解析 MySQL 的 binlog 日志時,默認使用 UTC 時區來處理時間字段。若…