跳转至

迭代器模式

分类:行为型模式。

类结构

classDiagram
    direction TB
    class Client
    class Aggregate {
        <<interface>>
        +createIterator() Iterator
    }
    class ConcreteAggregate {
        -List items
        +createIterator() Iterator
    }
    class Iterator {
        <<interface>>
        +hasNext() bool
        +next() Item
    }
    class ConcreteIterator {
        -int position
        +hasNext() bool
        +next() Item
    }
    Client ..> Aggregate : 取得迭代器
    Client ..> Iterator : 遍历
    Aggregate <|.. ConcreteAggregate
    Iterator <|.. ConcreteIterator
    ConcreteAggregate ..> ConcreteIterator : 创建
    ConcreteIterator --> ConcreteAggregate : 访问集合

角色定义

角色 定义
Client(客户) 向集合请求迭代器,通过迭代器接口遍历元素。
Aggregate(聚合接口) 声明获取迭代器的方法,屏蔽集合的内部表示。
ConcreteAggregate(具体聚合) 保存实际元素,并创建能遍历自身的具体迭代器。
Iterator(迭代器接口) 定义检查是否有下一个元素、取得下一元素等遍历操作。
ConcreteIterator(具体迭代器) 持有集合引用并维护自己的遍历位置,实现对应的遍历规则。

Head First 示例:合并早餐与午餐菜单

第 9 章中,煎饼屋用列表保存早餐菜单,餐厅用数组保存午餐菜单,服务员需要统一遍历它们。下面采用作者 2020 年第二版配套仓库的 iterator/dinermerger,即自定义 Iterator 接口的版本;其他目录还展示了使用 Java 标准迭代器的演进。

两个菜单都提供 createIterator()。服务员只调用迭代器,不需要为数组和列表各写一套访问逻辑。图中省略菜单项字段和具体菜名,集合在源码中分别是 List<MenuItem>、MenuItem[]。

示例类型 模式角色 职责
Waitress 客户 持有两个 Menu 引用,取得迭代器后统一打印菜单。
Menu 聚合接口 声明 createIterator(),隐藏具体集合表示。
PancakeHouseMenu / DinerMenu 具体聚合 分别用列表、固定容量数组保存菜单项。
Iterator 迭代器接口 这是示例自定义接口,声明 hasNext()、next()。
PancakeHouseMenuIterator / DinerMenuIterator 具体迭代器 分别维护列表、数组的遍历位置,并返回 MenuItem。
MenuItem 集合元素 保存一道菜的名称、说明、价格及是否素食等信息。

示例 UML

classDiagram
    direction TB
    class Waitress {
        +printMenu()
    }
    class Menu {
        <<interface>>
        +createIterator() Iterator
    }
    class PancakeHouseMenu {
        +createIterator() Iterator
    }
    class DinerMenu {
        +createIterator() Iterator
    }
    class Iterator {
        <<interface>>
        +hasNext() boolean
        +next() MenuItem
    }
    class PancakeHouseMenuIterator {
        int position
        +hasNext() boolean
        +next() MenuItem
    }
    class DinerMenuIterator {
        int position
        +hasNext() boolean
        +next() MenuItem
    }
    class MenuItem
    Waitress --> Menu : 请求遍历
    Waitress ..> Iterator : 统一读取
    Menu <|.. PancakeHouseMenu
    Menu <|.. DinerMenu
    Iterator <|.. PancakeHouseMenuIterator
    Iterator <|.. DinerMenuIterator
    PancakeHouseMenu ..> PancakeHouseMenuIterator : 创建
    DinerMenu ..> DinerMenuIterator : 创建
    PancakeHouseMenuIterator --> "0..*" MenuItem : 列表中的元素
    DinerMenuIterator --> "0..*" MenuItem : 数组中的元素

协作过程

  1. 装配代码把早餐菜单和午餐菜单作为 Menu 传给 Waitress。
  2. 服务员分别调用 createIterator(),获得对应数据结构的迭代器。
  3. 同一个打印循环调用 hasNext()、next(),再读取返回菜单项的信息。
  4. 遍历位置保存在各迭代器中,服务员不再区分数组下标和列表访问方式。

配套源码(2020 年第二版,固定版本):

评论