迭代器模式:遍历聚合对象的统一接口

FreeGuideOnline 最新 2026-06-18

迭代器模式:遍历聚合对象的统一接口

摘要
你是否曾在代码中为了遍历不同的集合而写满各种 for 循环?迭代器模式提供了一种统一的方式来顺序访问聚合对象中的元素,无需暴露其底层表示。本教程带你从零掌握迭代器模式的核心思想、结构与实战应用。


1. 模式定义

迭代器模式(Iterator Pattern) 是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

简单说:把遍历行为从聚合对象中抽离出来,封装到一个独立的迭代器对象中。这样你可以使用相同的接口遍历列表、树、图等任何集合。


2. 为什么需要迭代器模式?

2.1 直面痛点

假设你有一个 List 和一个 BinaryTree,遍历它们的方式完全不同:

# 遍历列表
for i in range(len(my_list)):
    print(my_list[i])

# 遍历二叉树?需要手动递归或栈操作,代码复杂且不统一

如果系统中存在多种集合,客户端代码会充斥着不同的遍历逻辑,导致:

  • 高耦合:客户端需要知道每种集合的内部结构。
  • 代码重复:遍历逻辑无法复用。
  • 难以扩展:新增一种集合,所有用到遍历的地方都要修改。

2.2 模式带来的优势

  • 统一接口:不管底层是数组、链表还是树,都通过 has_next()next() 访问元素。
  • 隔离变化:集合改变内部表示,只要迭代器接口不变,客户端代码无需更改。
  • 支持多种遍历:可以为同一个聚合定义多个迭代器(正序、倒序、DFS、BFS)。
  • 简化聚合接口:聚合类不再需要包含遍历相关方法。

3. 模式结构

迭代器模式通常包含四个角色:

角色 说明
抽象迭代器(Iterator) 定义访问和遍历元素的接口,如 first()next()has_next()current_item()
具体迭代器(ConcreteIterator) 实现迭代器接口,记录遍历过程中的当前位置
抽象聚合(Aggregate) 定义一个创建迭代器对象的接口
具体聚合(ConcreteAggregate) 实现创建迭代器的接口,返回一个适合遍历该聚合的具体迭代器实例

UML 简图(文字描述):
Client 持有 Aggregate,通过 Aggregate.create_iterator() 获得 Iterator,然后使用 Iterator 方法遍历聚合内部元素。


4. 动手实现:一个通用集合迭代器

我们用 Python 实现一个简单的书架和借书清单迭代器。

4.1 抽象迭代器与聚合

from abc import ABC, abstractmethod

class Iterator(ABC):
    @abstractmethod
    def has_next(self) -> bool:
        pass

    @abstractmethod
    def next(self):
        pass

class Aggregate(ABC):
    @abstractmethod
    def create_iterator(self) -> Iterator:
        pass

4.2 具体聚合:书架

书架内部使用 list 存储书籍,但外部只能通过迭代器访问。

class BookShelf(Aggregate):
    def __init__(self):
        self._books = []

    def add_book(self, book: str):
        self._books.append(book)

    def __len__(self):
        return len(self._books)

    def _get_book_at(self, index: int):
        return self._books[index]

    def create_iterator(self) -> Iterator:
        return BookShelfIterator(self)

4.3 具体迭代器

class BookShelfIterator(Iterator):
    def __init__(self, book_shelf: BookShelf):
        self._book_shelf = book_shelf
        self._index = 0

    def has_next(self) -> bool:
        return self._index < len(self._book_shelf)

    def next(self):
        if not self.has_next():
            raise StopIteration("没有更多书了")
        book = self._book_shelf._get_book_at(self._index)
        self._index += 1
        return book

4.4 客户端使用

if __name__ == "__main__":
    shelf = BookShelf()
    shelf.add_book("《设计模式》")
    shelf.add_book("《重构》")
    shelf.add_book("《代码整洁之道》")

    iterator = shelf.create_iterator()
    while iterator.has_next():
        print(iterator.next())

输出:

《设计模式》
《重构》
《代码整洁之道》

注意:客户端完全不依赖 _books 列表的存在。未来如果 BookShelf 换成 tupleLinkedList,只要迭代器更新,客户端代码保持不变。


5. 再进一步:支持多种遍历策略

同一个聚合可以提供多个迭代器。例如,我们为书架增加一个倒序迭代器

class ReverseBookShelfIterator(Iterator):
    def __init__(self, book_shelf: BookShelf):
        self._book_shelf = book_shelf
        self._index = len(book_shelf) - 1

    def has_next(self) -> bool:
        return self._index >= 0

    def next(self):
        if not self.has_next():
            raise StopIteration()
        book = self._book_shelf._get_book_at(self._index)
        self._index -= 1
        return book

BookShelf 中添加新方法:

def create_reverse_iterator(self) -> Iterator:
    return ReverseBookShelfIterator(self)

客户端可以自由选择迭代顺序,而书架本身不需要存放额外的游标信息。


6. 迭代器模式在现实中的身影

许多语言内置迭代器概念,你已经在不知不觉中使用了它:

  • Pythonfor item in collection: 依赖对象的 __iter__()__next__() 协议,本质就是迭代器模式。
  • Javajava.util.Iterator 接口和 foreach 循环。
  • C++:STL 迭代器是迭代器模式的经典实现,将算法与容器分离。
  • 数据库游标:Cursor 就是一个迭代器,允许你逐行读取查询结果,而不关心底层存储结构。

7. 适用场景与注意事项

7.1 什么时候该用

  • 需要为多种聚合对象提供统一的遍历方式。
  • 需要隐藏集合的内部表示(数组、链表、红黑树等)。
  • 需要支持对一个聚合对象的多种遍历方式(顺序、逆序、中序遍历等)。
  • 希望对遍历过程进行控制和暂停(如使用 has_next 判断边界,而非一次性全部取出)。

7.2 权衡利弊

优点 缺点
符合单一职责原则:将遍历行为与集合管理分离 对于简单遍历(如数组),使用迭代器可能增加代码复杂度
开闭原则:新增聚合和迭代器无需修改现有代码 某些情况下,直接使用语言内置的迭代器语法更简单
可以同时存在多个迭代器,各不干扰 若聚合频繁修改,需额外机制保证迭代器一致性(如 fail-fast)

8. 高频面试问题速答

问:迭代器模式和普通 for 循环有什么区别?
答:普通循环直接依赖集合的底层结构(索引或指针),迭代器将遍历抽象出来,让客户端不用关心你用的是 list[0] 还是链表头结点。

问:如何实现一个可被 for-in 遍历的自定义类?
答:实现 __iter__() 返回一个迭代器对象,该对象需实现 __next__() 方法并在末尾抛出 StopIteration

问:迭代器模式与组合模式有什么关系?
答:经常一起出现。组合模式产生树形结构,迭代器模式可以轻松实现深度优先或广度优先遍历整棵树。


9. 完整示例代码(一站式参考)

from abc import ABC, abstractmethod

# ---------- 抽象层 ----------
class Iterator(ABC):
    @abstractmethod
    def has_next(self): pass

    @abstractmethod
    def next(self): pass

class Aggregate(ABC):
    @abstractmethod
    def create_iterator(self): pass

# ---------- 具体聚合 ----------
class BookShelf(Aggregate):
    def __init__(self):
        self._books = []

    def add_book(self, book):
        self._books.append(book)

    def __len__(self):
        return len(self._books)

    def _get_book_at(self, index):
        return self._books[index]

    def create_iterator(self):
        return BookShelfIterator(self)

    def create_reverse_iterator(self):
        return ReverseBookShelfIterator(self)

# ---------- 具体迭代器 ----------
class BookShelfIterator(Iterator):
    def __init__(self, shelf):
        self._shelf = shelf
        self._index = 0

    def has_next(self):
        return self._index < len(self._shelf)

    def next(self):
        if not self.has_next():
            raise StopIteration
        book = self._shelf._get_book_at(self._index)
        self._index += 1
        return book

class ReverseBookShelfIterator(Iterator):
    def __init__(self, shelf):
        self._shelf = shelf
        self._index = len(shelf) - 1

    def has_next(self):
        return self._index >= 0

    def next(self):
        if not self.has_next():
            raise StopIteration
        book = self._shelf._get_book_at(self._index)
        self._index -= 1
        return book

# ---------- 客户端 ----------
if __name__ == "__main__":
    shelf = BookShelf()
    for title in ["A", "B", "C"]:
        shelf.add_book(title)

    print("正序:")
    it = shelf.create_iterator()
    while it.has_next():
        print(it.next())

    print("倒序:")
    rev_it = shelf.create_reverse_iterator()
    while rev_it.has_next():
        print(rev_it.next())

10. 总结

迭代器模式的核心思想是将遍历与集合解耦。通过引入统一的迭代器接口,你将获得:

  • 更清晰的代码结构(聚合专心管理数据,迭代器专注遍历)
  • 易于切换底层数据结构的能力
  • 支持多种遍历算法而无需修改已有代码

当你下次为“如何统一遍历不同类型的集合”而困扰时,迭代器模式就是那个久经考验的答案。

设计原则共鸣:单一职责原则(遍历职责分离)、开闭原则(扩展新的迭代器无需修改聚合)、依赖倒转原则(依赖抽象迭代器,而非具体集合)。


本教程仅供“免费在线教程”网站学习使用,欢迎分享、收藏。掌握迭代器,轻松遍历万物!