设计模式之迭代器模式

2024-02-10 08:46:11 浏览数 (1)

1. 基本概念

1.1 定义

迭代器模式(Iterator Pattern)是一种行为型设计模式,用于提供一种顺序访问聚合对象中各个元素的方法,而无需暴露其内部表示。它定义了一种访问聚合对象元素的统一接口,使得可以在不暴露聚合对象内部结构的情况下,按顺序访问聚合对象中的元素。

1.2 主要角色

  • 迭代器(Iterator): 定义访问和遍历元素的接口。
  • 具体迭代器(ConcreteIterator): 实现迭代器接口,负责实际遍历聚合对象并跟踪当前位置。
  • 聚合(Aggregate): 定义创建迭代器对象的接口,可以是集合或容器。
  • 具体聚合(ConcreteAggregate): 实现聚合接口,创建并返回具体迭代器。

1.3 工作流程

  1. 客户端使用迭代器: 客户端通过迭代器接口访问聚合对象的元素,而不直接访问聚合对象。
  2. 迭代器创建: 聚合对象通过实现聚合接口创建具体的迭代器对象。
  3. 迭代过程: 迭代器负责跟踪聚合对象中的当前位置,提供访问下一个元素和判断是否还有元素的方法。
  4. 客户端遍历: 客户端使用迭代器的方法遍历聚合对象中的元素,而无需了解聚合对象的内部结构。

2. 使用场景

迭代器模式在以下情景中可以得到有效的应用:

  1. 遍历聚合对象: 当需要遍历一个聚合对象的元素而不暴露其内部表示时,使用迭代器模式。这样可以使得聚合对象和遍历算法相互分离,使得系统更具灵活性。
  2. 多种遍历方式: 当一个聚合对象需要提供多种不同的遍历方式,而且这些遍历方式可能会在未来扩展,可以使用迭代器模式。迭代器模式允许在不修改聚合对象的情况下定义新的迭代器。
  3. 访问聚合对象的不同部分: 当需要按顺序访问一个聚合对象的不同部分,并且不暴露其内部表示时,可以使用迭代器模式。这样可以实现逐步抽象,对聚合对象的不同部分进行访问。
  4. 封装遍历算法: 当遍历算法较为复杂,或者可能发生变化时,可以使用迭代器模式将遍历算法封装在迭代器中。这样,客户端就无需关心遍历算法的实现细节。
  5. 支持逆向遍历: 在一些场景下,可能需要支持逆向遍历,即从后往前遍历聚合对象的元素。迭代器模式可以方便地支持这种需求。

迭代器模式适用于需要遍历一个聚合对象的场景,并且希望在遍历时能够封装遍历算法,以及在未来能够灵活地扩展和修改遍历方式的情况。

3. 优缺点

优点:

  1. 简化客户端代码: 迭代器模式将遍历操作封装在迭代器中,使得客户端无需关心集合内部结构,通过迭代器接口统一访问元素,简化了客户端代码。
  2. 支持多种遍历方式: 可以为同一聚合对象提供不同的迭代器,从而支持多种不同的遍历方式,满足不同的需求,而不需要修改聚合对象的代码。
  3. 封装性良好: 迭代器模式将遍历算法封装在迭代器中,使得遍历逻辑独立于集合对象,实现了聚合对象和迭代器对象之间的分离。
  4. 单一职责原则: 聚合对象只负责存储数据,而迭代器对象负责遍历,每个对象具有单一职责,符合单一职责原则。
  5. 增加新的聚合类和迭代器类方便: 可以通过扩展迭代器接口和聚合接口,轻松地添加新的聚合类和迭代器类,无需修改现有代码。

缺点:

  1. 类数目增加: 引入迭代器模式会增加一些额外的类,包括具体迭代器和具体聚合类,可能会使得系统类数目增加,复杂性增加。
  2. 迭代器抽象程度较高: 如果迭代器的抽象程度过高,实现的难度会增加。如果迭代器过于灵活,可能导致不同的迭代器实现差异较大。
  3. 不适用于简单集合: 对于一些简单的集合对象,使用迭代器模式可能会显得过于繁琐,不切实际。
  4. 性能问题: 在某些情况下,使用迭代器模式可能会引入一些性能问题,特别是在处理大量数据时。

4. 示例代码:

下面是一个简单的迭代器模式的示例,其中包括一个具体聚合类MyList和一个具体迭代器类ListIterator

代码语言:go复制
package main

import "fmt"

// Iterator Interface
type Iterator interface {
	HasNext() bool
	Next() string
}

// Aggregate Interface
type List interface {
	CreateIterator() Iterator
}

// ConcreteIterator
type ListIterator struct {
	list  []string
	index int
}

func NewListIterator(list []string) *ListIterator {
	return &ListIterator{list: list, index: 0}
}

func (li *ListIterator) HasNext() bool {
	return li.index < len(li.list)
}

func (li *ListIterator) Next() string {
	if li.HasNext() {
		value := li.list[li.index]
		li.index  
		return value
	}
	return ""
}

// ConcreteAggregate
type MyList struct {
	elements []string
}

func NewMyList() *MyList {
	return &MyList{elements: make([]string, 0)}
}

func (ml *MyList) AddElement(element string) {
	ml.elements = append(ml.elements, element)
}

func (ml *MyList) CreateIterator() Iterator {
	return NewListIterator(ml.elements)
}

// Client
func main() {
	myList := NewMyList()
	myList.AddElement("Item 1")
	myList.AddElement("Item 2")
	myList.AddElement("Item 3")

	iterator := myList.CreateIterator()

	for iterator.HasNext() {
		fmt.Println(iterator.Next())
	}
}

在这个例子中,Iterator是迭代器接口,List是聚合接口,而ListIterator是具体迭代器实现。MyList是具体聚合实现。客户端通过迭代器访问MyList中的元素,而不需要了解MyList的内部结构。

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。

blog: mengbin

Github: mengbin92

cnblogs: 恋水无意

腾讯云开发者社区:孟斯特


0 人点赞