迭代器模式¶
分类:行为型模式。
类结构¶
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 : 数组中的元素
协作过程¶
- 装配代码把早餐菜单和午餐菜单作为
Menu传给Waitress。 - 服务员分别调用
createIterator(),获得对应数据结构的迭代器。 - 同一个打印循环调用
hasNext()、next(),再读取返回菜单项的信息。 - 遍历位置保存在各迭代器中,服务员不再区分数组下标和列表访问方式。
配套源码(2020 年第二版,固定版本):