1. 迭代器模式概述

1.1 什麼是迭代器模式?

迭代器模式是一種行為型設計模式,其核心思想是提供一種方法來訪問聚合對象中的元素,而無需暴露聚合的內部結構。根據GoF(Gang of Four)在《設計模式:可複用面向對象軟件的基礎》中的定義,迭代器模式的目的是:“提供一種方法順序訪問一個聚合對象中各個元素,而又不需暴露該對象的內部表示。”

在迭代器模式中,迭代器(Iterator)負責遍歷邏輯,聚合對象(Aggregate)提供創建迭代器的接口。客户端通過迭代器獲取元素序列,而不關心聚合是數組、鏈表、樹還是自定義結構。這實現了遍歷與聚合的解耦,支持多種遍歷方式(如順序、逆序、過濾)。

迭代器模式符合開閉原則(OCP),允許在不修改聚合類的情況下添加新迭代器;同時支持單一職責原則(SRP),聚合專注數據管理,迭代器專注遍歷。Java中,java.util.Iteratorjava.lang.Iterable是標準實現,廣泛用於Collection框架。

與歷史對話中的解釋器模式(語法樹遞歸解釋)不同,迭代器模式更注重順序訪問而非樹狀解釋;與命令模式(請求封裝,支持Undo)相比,迭代器處理數據流而非行為歷史;與責任鏈模式(線性傳遞)類似,但迭代器是拉取式(pull)而非推送式;與策略模式(算法切換)不同,它參數化遍歷行為而非業務邏輯。

迭代器模式的本質是遍歷抽象化內部隱藏。它將訪問邏輯從數據結構中分離,便於管理複雜集合,尤其在需要統一遍歷接口的系統中表現出色。

1.2 迭代器模式的核心組成

迭代器模式通常涉及以下幾個關鍵角色:

  1. Iterator(迭代器接口):聲明遍歷操作,如hasNext()next(),有時包括remove()
  2. ConcreteIterator(具體迭代器):實現Iterator接口,維護當前遊標、聚合引用。
  3. Aggregate(聚合接口):聲明創建迭代器的工廠方法,如iterator()
  4. ConcreteAggregate(具體聚合):實現Aggregate,提供具體迭代器實例。
  5. Client(客户端):使用聚合的迭代器遍歷元素。

迭代器模式的工作流程如下:

  1. 客户端獲取聚合的迭代器。
  2. 客户端循環調用hasNext()檢查、next()獲取元素。
  3. 迭代器內部管理位置,避免客户端直接訪問聚合。
  4. 可選支持remove()安全刪除。

迭代器模式的靈活性在於,支持外部迭代器(客户端控制)和內部迭代器(聚合控制回調),以及失效安全(fail-fast)機制檢測併發修改。

2. 迭代器模式的原理與結構

2.1 迭代器模式的UML類圖

以下是迭代器模式的典型UML類圖,展示其結構:

+------------------+       +------------------+
|     Client       |       |   Aggregate      |
+------------------+       +------------------+
|                  |<----->| + iterator()     |
+------------------+       +------------------+
                                     ^
                                     |
                +--------------------+--------------------+
                |                                         |
   +---------------------+                  +---------------------+
   |     Iterator        |                  | ConcreteIterator    |
   +---------------------+                  +---------------------+
   | + hasNext()         |<-----------------| - aggregate         |
   | + next()            |                  | - cursor            |
   | + remove() (opt)    |                  | + hasNext()         |
   +---------------------+                  | + next()            |
                                     ^      +---------------------+
                                     |               ^
                                     |               |
                              +------------------+ 
                              | ConcreteAggregate|
                              +------------------+
                              | + iterator()     |
                              | - elements       |
                              +------------------+
  • Client:使用迭代器遍歷。
  • Aggregate:工廠接口。
  • Iterator:遍歷協議。
  • ConcreteIterator:狀態管理。
  • ConcreteAggregate:數據容器。

此結構支持多迭代器併發遍歷。

2.2 迭代器模式的變體

迭代器模式根據遍歷需求可分為以下變體:

  1. 外部迭代器:客户端拉取元素(Java標準)。
  2. 內部迭代器:聚合推送元素到回調(如Java 8 forEach)。
  3. 失效快速迭代器:併發修改拋ConcurrentModificationException
  4. 失效安全迭代器:複製快照,支持修改(如CopyOnWriteArrayList)。
  5. 過濾/映射迭代器:裝飾器模式擴展,支持條件遍歷。
  6. 樹狀迭代器:深度優先、廣度優先遍歷。

在Java中,ListIterator擴展支持雙向遍歷;Stream API是函數式迭代器。

3. 迭代器模式的Java實現

為深入理解迭代器模式,以下通過三個場景展示其Java實現:自定義數組列表迭代器(基本版)、鏈表逆序迭代器(雙向版)和樹狀結構深度遍歷迭代器(複合版)。

3.1 自定義數組列表:基本順序迭代器

迭代器模式常用於集合遍歷,模擬ArrayList

3.1.1 聚合接口與具體聚合

// 聚合接口
interface MyCollection<E> {
    MyIterator<E> iterator();
    void add(E element);
    int size();
}

// 具體聚合:數組列表
class MyArrayList<E> implements MyCollection<E> {
    private Object[] elements = new Object[10];
    private int size = 0;

    @Override
    public void add(E element) {
        if (size == elements.length) {
            elements = Arrays.copyOf(elements, size * 2);
        }
        elements[size++] = element;
    }

    @Override
    public int size() {
        return size;
    }

    @SuppressWarnings("unchecked")
    public E get(int index) {
        if (index >= size) throw new IndexOutOfBoundsException();
        return (E) elements[index];
    }

    @Override
    public MyIterator<E> iterator() {
        return new ArrayIterator();
    }

    private class ArrayIterator implements MyIterator<E> {
        private int cursor = 0;
        private int expectedModCount = modCount; // 失效快速

        @Override
        public boolean hasNext() {
            checkForComodification();
            return cursor < size;
        }

        @SuppressWarnings("unchecked")
        @Override
        public E next() {
            checkForComodification();
            if (cursor >= size) throw new NoSuchElementException();
            return (E) elements[cursor++];
        }

        @Override
        public void remove() {
            // 簡化實現:不支持或拋異常
            throw new UnsupportedOperationException();
        }

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

3.1.2 迭代器接口

// 迭代器接口
interface MyIterator<E> {
    boolean hasNext();
    E next();
    void remove(); // 可選
}

3.1.3 客户端代碼

public class ArrayIteratorDemo {
    public static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<>();
        list.add("蘋果");
        list.add("香蕉");
        list.add("橙子");

        MyIterator<String> it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        // 輸出:蘋果 香蕉 橙子
    }
}

運行結果:

蘋果
香蕉
橙子

分析:此示例實現失效快速機制(modCount)。內部類訪問私有字段。易擴展支持remove。

3.2 鏈表:支持逆序的雙向迭代器

擴展為雙向鏈表,支持正序/逆序。

3.2.1 節點與聚合

// 節點
class Node<E> {
    E data;
    Node<E> prev, next;

    Node(E data) {
        this.data = data;
    }
}

// 具體聚合:雙向鏈表
class MyLinkedList<E> implements MyCollection<E> {
    private Node<E> head, tail;
    private int size = 0;
    private int modCount = 0;

    @Override
    public void add(E element) {
        Node<E> newNode = new Node<>(element);
        if (tail == null) {
            head = tail = newNode;
        } else {
            tail.next = newNode;
            newNode.prev = tail;
            tail = newNode;
        }
        size++;
        modCount++;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public MyIterator<E> iterator() {
        return new ForwardIterator();
    }

    public MyIterator<E> reverseIterator() {
        return new ReverseIterator();
    }

    // 正序迭代器
    private class ForwardIterator implements MyIterator<E> {
        private Node<E> current = new Node<>(null); // 哨兵
        { current.next = head; }
        private int expectedModCount = modCount;

        @Override
        public boolean hasNext() {
            check();
            return current.next != null;
        }

        @Override
        public E next() {
            check();
            current = current.next;
            return current.data;
        }

        @Override
        public void remove() {
            // 實現鏈表刪除,更新modCount
            throw new UnsupportedOperationException(); // 簡化
        }

        private void check() {
            if (expectedModCount != modCount) throw new ConcurrentModificationException();
        }
    }

    // 逆序迭代器
    private class ReverseIterator implements MyIterator<E> {
        private Node<E> current = new Node<>(null);
        { current.prev = tail; }
        private int expectedModCount = modCount;

        @Override
        public boolean hasNext() {
            check();
            return current.prev != null;
        }

        @Override
        public E next() {
            check();
            current = current.prev;
            return current.data;
        }

        private void check() {
            if (expectedModCount != modCount) throw new ConcurrentModificationException();
        }
    }
}

3.2.2 客户端代碼

public class LinkedIteratorDemo {
    public static void main(String[] args) {
        MyLinkedList<String> list = new MyLinkedList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        System.out.println("正序:");
        MyIterator<String> forward = list.iterator();
        while (forward.hasNext()) {
            System.out.println(forward.next());
        }

        System.out.println("逆序:");
        MyIterator<String> reverse = list.reverseIterator();
        while (reverse.hasNext()) {
            System.out.println(reverse.next());
        }
    }
}

運行結果:

正序:
A
B
C
逆序:
C
B
A

分析:此示例支持多迭代器變體。哨兵節點簡化邊界。適用於需要靈活遍歷的結構。

3.3 樹狀結構:深度優先迭代器

結合複合模式,遍歷二叉樹。

3.3.1 樹節點與聚合

// 樹節點
class TreeNode<E> {
    E data;
    TreeNode<E> left, right;

    TreeNode(E data) {
        this.data = data;
    }
}

// 具體聚合:二叉樹
class BinaryTree<E> implements MyCollection<E> {
    private TreeNode<E> root;
    private int size = 0;

    public void insert(E data) {
        // 簡化:構建樹
        if (root == null) {
            root = new TreeNode<>(data);
        } else {
            // 實際插入邏輯省略
        }
        size++;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public MyIterator<E> iterator() {
        return new DFSIterator();
    }

    // 深度優先迭代器(非遞歸,使用棧)
    private class DFSIterator implements MyIterator<E> {
        private Stack<TreeNode<E>> stack = new Stack<>();

        public DFSIterator() {
            if (root != null) pushLeft(root);
        }

        private void pushLeft(TreeNode<E> node) {
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
        }

        @Override
        public boolean hasNext() {
            return !stack.isEmpty();
        }

        @Override
        public E next() {
            if (!hasNext()) throw new NoSuchElementException();
            TreeNode<E> node = stack.pop();
            pushLeft(node.right);
            return node.data;
        }
    }
}

3.3.2 客户端代碼(構建樹)

public class TreeIteratorDemo {
    public static void main(String[] args) {
        BinaryTree<Integer> tree = new BinaryTree<>();
        // 構建樹:根1,左2右3,2左4
        // 手動構建
        tree.root = new TreeNode<>(1);
        tree.root.left = new TreeNode<>(2);
        tree.root.right = new TreeNode<>(3);
        tree.root.left.left = new TreeNode<>(4);
        tree.size = 4;

        MyIterator<Integer> it = tree.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        // 輸出:4 2 1 3 (中序變體)
    }
}

分析:非遞歸DFS使用棧,避免遞歸溢出。易擴展BFS(隊列)。

4. 迭代器模式的應用場景

4.1 集合框架遍歷

  • Java Collections:ArrayList.iterator()
  • 數據庫結果集:ResultSet

4.2 數據流處理

  • 文件行迭代:BufferedReader.lines()
  • 網絡流:字節迭代器。

4.3 樹/圖遍歷

  • DOM樹:節點迭代。
  • 文件系統目錄遍歷。

4.4 自定義數據結構

  • 優先隊列、跳錶迭代。
  • 分頁數據懶加載。

4.5 其他場景

  • 遊戲實體遍歷:場景對象迭代。
  • 日誌記錄器:事件流迭代。

5. 迭代器模式的優缺點

5.1 迭代器模式的優點

  1. 解耦性:遍歷與聚合分離。
  2. 統一接口:多數據結構統一遍歷。
  3. 支持多遍歷:併發、正逆序。
  4. 安全性:隱藏內部,失效檢測。
  5. 擴展性:易添加過濾/轉換迭代器。

5.2 迭代器模式的缺點

  1. 開銷增加:簡單數組直接索引更快。
  2. 狀態管理:多迭代器需跟蹤遊標。
  3. 不支持隨機訪問:順序迭代侷限。
  4. 併發複雜:失效機制需同步。
  5. 內存消耗:棧/隊列輔助結構。

6. 迭代器模式與其他設計模式的對比

6.1 迭代器模式 vs. 解釋器模式

  • 迭代器模式:順序訪問元素。
  • 解釋器模式(歷史對話):樹遞歸解釋。

迭代器可遍歷AST節點。

6.2 迭代器模式 vs. 命令模式

  • 迭代器模式:數據拉取。
  • 命令模式:行為執行。

命令隊列可用迭代器遍歷。

6.3 迭代器模式 vs. 責任鏈模式

  • 迭代器模式:拉取式遍歷。
  • 責任鏈模式:推送式處理。

鏈節點可用迭代器訪問。

6.4 迭代器模式 vs. 訪問者模式

  • 迭代器模式:客户端控制遍歷。
  • 訪問者模式:元素接受訪問者。

結合使用:迭代器提供元素,訪問者操作。

6.5 與複合模式結合

樹迭代器遍歷複合結構。

7. 迭代器模式在實際項目中的案例分析

7.1 Java Collection Framework

List<String> list = new ArrayList<>();
list.add("Java");
for (String s : list) { // 增強for使用iterator
    System.out.println(s);
}

內部ArrayList.Itr實現失效快速。

7.2 Stream API

list.stream().filter(s -> s.startsWith("J")).forEach(System.out::println);

Spliterator是並行迭代器。

7.3 JDBC ResultSet

while (rs.next()) {
    System.out.println(rs.getString(1));
}

行迭代器封裝數據庫遊標。

8. 迭代器模式的注意事項與最佳實踐

8.1 設計注意事項

  • 失效機制:使用modCount檢測修改。
  • 移除安全:remove後調整遊標。
  • 空聚合:hasNext返回false。
  • 線程安全:同步或CopyOnWrite。

8.2 性能優化

  • 懶加載:生成器式迭代器。
  • 批量next:減少方法調用。
  • 並行:Spliterator支持fork。
  • 緩存:預取元素。
Spliterator<String> spliterator = list.spliterator();
spliterator.forEachRemaining(System.out::println);

8.3 常見坑點

  • ConcurrentModificationException:迭代中修改。
  • 遊標越界:未檢查hasNext。
  • 內存泄漏:長生命週期迭代器持聚合。
  • 無限迭代:循環結構未終止。

8.4 結合Java現代特性

Java 8+ Iterable默認方法:

interface MyCollection<E> extends Iterable<E> {
    default void forEach(Consumer<? super E> action) {
        for (E e : this) action.accept(e);
    }
}

Record簡化節點。