迭代器模式(Iterator Pattern)
迭代器模式(Iterator Pattern)
1. 知识点总结
迭代器模式是一种行为型设计模式,核心思想是:
提供一种方法顺序访问聚合对象中的各个元素,而无需暴露该对象的内部表示。
在 Go 中,如果只是遍历 slice 或 map,内置的 range 关键字通常已经足够。迭代器模式更适用于以下场景:
- 集合内部结构复杂,比如树、图、链表;
- 需要为同一种集合提供多种遍历方式(正序、逆序、前序、后序等);
- 需要多个独立的迭代器同时遍历同一个集合,各自维护自己的位置。
适用场景
- 希望统一遍历接口,屏蔽底层数据结构的差异;
- 需要在不暴露集合内部实现的情况下提供遍历能力;
- 需要支持并发或多种遍历策略。
优缺点
| 优点 | 缺点 |
|---|---|
| 隐藏集合内部结构,客户端只依赖迭代器接口 | 对于简单集合,直接用 range 更简洁 |
| 支持多种遍历方式和多个并发迭代器 | 遍历时修改集合可能导致迭代器失效 |
| 遍历逻辑从集合类中分离,职责清晰 | 额外引入接口和类型,增加了代码量 |
2. 示例代码
下面用书架(BookShelf)和书籍迭代器(BookIterator)来演示。客户端不需要知道书架内部是切片、链表还是树。
package main
import "fmt"
// Book 是聚合对象中的元素。
type Book struct {
Title string
Author string
}
// Iterator 声明顺序访问集合的接口。
type Iterator interface {
HasNext() bool
Next() Book
}
// Aggregate 是拥有迭代器的集合接口。
type Aggregate interface {
Iterator() Iterator
}
// BookShelf 是具体集合,内部用切片存储书籍。
type BookShelf struct {
books []Book
}
func (b *BookShelf) Add(book Book) {
b.books = append(b.books, book)
}
func (b *BookShelf) Iterator() Iterator {
return &BookIterator{books: b.books}
}
// BookIterator 维护当前遍历位置,不暴露底层切片。
type BookIterator struct {
books []Book
index int
}
func (bi *BookIterator) HasNext() bool {
return bi.index < len(bi.books)
}
func (bi *BookIterator) Next() Book {
book := bi.books[bi.index]
bi.index++
return book
}
func main() {
shelf := &BookShelf{}
shelf.Add(Book{Title: "Go语言圣经", Author: "Alan A.A. Donovan"})
shelf.Add(Book{Title: "Go语言设计与实现", Author: "Draven"})
shelf.Add(Book{Title: "数据结构与算法", Author: "LeetCode"})
it := shelf.Iterator()
for it.HasNext() {
book := it.Next()
fmt.Printf("《%s》 - %s\n", book.Title, book.Author)
}
}
3. 运行结果
《Go语言圣经》 - Alan A.A. Donovan
《Go语言设计与实现》 - Draven
《数据结构与算法》 - LeetCode
4. 关键点复盘
- 统一遍历接口:无论集合是切片、链表还是树,只要实现
Iterator(),客户端代码就可以用HasNext()+Next()统一遍历。 - 独立游标:每个迭代器维护自己的
index,同一个集合可以同时存在多个迭代器,互不干扰。 - 不暴露内部结构:客户端拿不到
BookShelf.books切片,只能通过迭代器访问,封装性更好。 - Go 中优先考虑
range:对于简单集合,range是更地道的写法;迭代器模式只在需要抽象遍历过程时使用。 - 与访问者模式的配合:迭代器负责“按顺序拿出元素”,访问者负责“对元素执行操作”。两者经常一起使用来遍历复杂对象结构。

浙公网安备 33010602011771号