[go] 迭代器模式

本文详细介绍了迭代器模式的概念,包括接口、具体实现和如何通过它隐藏复杂数据结构。阐述了模式的优点如单一职责原则和开闭原则,同时也讨论了可能的缺点。展示了在Go语言中的示例代码,以及何时适合使用此模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迭代器模式

提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露其内部的表示。

模型说明

  • Iterator: 接口声明了遍历集合所需的操作: 获取下一个元素、 获取当前位置和重新开始迭代等。

  • IterableCollection: 接口声明一个或多个方法来获取与集合兼容的迭代器。 请注意, 返回方法的类型必须被声明为迭代器接口, 因此具体集合可以返回各种不同种类的迭代器。

  • ConcreteIterator: 实现遍历集合的一种特定算法。 迭代器对象必须跟踪自身遍历的进度。 这使得多个迭代器可以相互独立地遍历同一集合。

  • ConcreteCollection: 会在客户端请求迭代器时返回一个特定的具体迭代器类实体。 你可能会琢磨, 剩下的集合代码在什么地方呢? 不用担心, 它也会在同一个类中。 只是这些细节对于实际模式来说并不重要, 所以我们将其省略了而已。

  • Client: 通过集合和迭代器的接口与两者进行交互。 这样一来客户端无需与具体类进行耦合, 允许同一客户端代码使用各种不同的集合和迭代器。

  • 客户端通常不会自行创建迭代器, 而是会从集合中获取。 但在特定情况下, 客户端可以直接创建一个迭代器 (例如当客户端需要自定义特殊迭代器时)。

优缺点

1.优点

  • *单一职责原则:*通过将体积庞大的遍历算法代码抽取为独立的类, 你可对客户端代码和集合进行整理。
  • *开闭原则:*你可实现新型的集合和迭代器并将其传递给现有代码, 无需修改现有代码。
  • 你可以并行遍历同一集合, 因为每个迭代器对象都包含其自身的遍历状态。
  • 相似的, 你可以暂停遍历并在需要时继续。

2.缺点

  • 如果你的程序只与简单的集合进行交互, 应用该模式可能会矫枉过正。
  • 对于某些特殊集合, 使用迭代器可能比直接遍历的效率低。

使用场景

  • 当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑),可以使用迭代器模式。
  • 使用该模式可以减少程序中重复的遍历代码。
  • 如果你希望代码能够遍历不同的甚至是无法预知的数据结构,可以使用迭代器模式。

参考代码

// iterator.go 迭代器接口
type Iterator interface {
	hasNext() bool
	getNext() *User
}
// userIterator.go 具体迭代器
type UserIterator struct {
	index int
	users []*User
}

func (u *UserIterator) hasNext() bool {
	if u.index < len(u.users) {
		return true
	}
	return false
}

func (u *UserIterator) getNext() *User {
	if u.hasNext() {
		user := u.users[u.index]
		u.index++
		return user
	}
	return nil
}
// collection.go 集合接口
type Collection interface {
	createIterator() Iterator
}
// userCollection.go 具体集合
type User struct {
	name string
	age  int
}

type UserCollection struct {
	users []*User
}

func (u *UserCollection) createIterator() Iterator {
	return &UserIterator{
		users: u.users,
	}
}
// main.go 客户端
func main() {
	user1 := &User{
		name: "a",
		age:  30,
	}
	user2 := &User{
		name: "b",
		age:  20,
	}

	userCollection := &UserCollection{
		users: []*User{user1, user2},
	}

	iterator := userCollection.createIterator()

	for iterator.hasNext() {
		user := iterator.getNext()
		fmt.Printf("User is %+v\n", user)
	}
}

output:

User is &{name:a age:30}
User is &{name:b age:20}
### Golang 中迭代器的实现与用法 #### 迭代器模式简介 迭代器模式提供了一种方法来顺序访问聚合对象中的各个元素,而无需暴露其内部表示。通过封装遍历逻辑,迭代器使得客户端可以一致地处理不同类型的集合。 #### 实现区块链迭代器的例子 下面展示了一个具体的例子——基于区块链数据结构的迭代器实现[^3]: ```go type BlockchainIterator struct { currentHash []byte db *bolt.DB } func (i *BlockchainIterator) Next() *Block { var block *Block // 使用事务读取当前哈希对应的区块 err := i.db.View(func(tx *bolt.Tx) error { bucket := tx.Bucket([]byte(blocksBucket)) encodedBlock := bucket.Get(i.currentHash) // 反序列化获取到的数据为 Block 对象 block = DeserializeBlock(encodedBlock) return nil }) if err != nil { log.Fatal(err) } // 更新下一个要访问的区块哈希值 i.currentHash = block.PrevBlockHash return block } ``` 此代码片段展示了如何创建一个 `BlockchainIterator` 类型以及它的成员函数 `Next()` 来逐步返回链上的每一个区块实例直到起始位置为止。 #### 自定义容器类的迭代器接口设计 为了更好地理解通用情况下的迭代器,在自定义容器类型上也可以应用类似的思路。这里给出一个简单的列表(slice)作为底层存储介质并为其构建迭代器的方式: ```go // 定义 List 和 Iterator 接口 type List interface { Get(index int) interface{} Len() int } type Iterator interface { HasNext() bool Next() interface{} } // SliceList 是实现了 List 接口的具体类型 type SliceList []interface{} func (l SliceList) Get(index int) interface{} { if index >= 0 && index < l.Len() { return (*reflect.ValueOf(&l).Elem().Index(index)).Interface() } panic("index out of range") } func (l SliceList) Len() int { return len(l) } // SliceIterator 构建于 SliceList 上面的一个简单迭代器 type SliceIterator struct { list List position int } func NewSliceIterator(list List) *SliceIterator { return &SliceIterator{list: list, position: -1} // 初始化指向前驱节点之前的位置(-1) } func (it *SliceIterator) HasNext() bool { return it.position+1 < it.list.Len() } func (it *SliceIterator) Next() interface{} { if !it.HasNext() { panic("no more elements to iterate over") } it.position++ element := it.list.Get(it.position) return element } ``` 上述代码中定义了两个主要组件:一个是代表可枚举集合的抽象类型 `List`;另一个则是用于遍历这些项目的工具 `Iterator` 。对于任意给定的支持这两种操作的对象来说都可以方便地生成相应的迭代行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员无锋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值