设计模式学习-使用go实现迭代器模式(Design pattern learning – Implementing iterator patterns using go)

  • 迭代器模式

    定义
    优点
    缺点
    适用范围
    代码实现
    参考

  • 定义
  • 优点
  • 缺点
  • 适用范围
  • 代码实现
  • 参考

迭代器模式

定义

迭代器模式(Iterator Design Pattern),也叫作游标模式(Cursor Design Pattern)。

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

这里的聚合对象也叫容器聚合对象,实质上及时包含一组对象的对象,例如数组、链表、树、图、跳表。迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一。

一个通俗的总结对于迭代器模式:

流水线上坐一天,每个包裹扫一遍。

优点

迭代器相比于 for 循环的优点

1、迭代器模式封装集合内部的复杂数据结构,开发者不需要了解如何遍历,直接使用容器提供的迭代器即可;

2、迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一;

3、迭代器模式让添加新的遍历算法更加容易,更符合开闭原则。除此之外,因为迭代器都实现自相同的接口,在开发中,基于接口而非实现编程,替换迭代器也变得更加容易。

缺点

由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

适用范围

1、访问一个聚合对象的内容而无须暴露它的内部表示;

2、需要为聚合对象提供多种遍历方式;

3、为遍历不同的聚合结构提供一个统一的接口。

代码实现

使用迭代器输出切片中的名字集合

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

type names []string

func (na names) NewIterator() *NameRepository {
	return &NameRepository{
		index: 0,
		names: na,
	}
}

type NameRepository struct {
	index int
	names names
}

func (nr *NameRepository) HasNext() bool {
	if nr.index < len(nr.names) {
		return true
	}
	return false
}

func (nr *NameRepository) Next() string {
	if nr.HasNext() {
		name := nr.names[nr.index]
		nr.index++
		return name
	}

	return ""
}

测试代码

func TestIterator(t *testing.T) {
	names := names{
		"小明", "小豆", "小龙",
	}
	nameRepository := names.NewIterator()
	for nameRepository.HasNext() {
		t.Log(nameRepository.Next())
	}
}

参考

【文中代码】https://github.com/boilingfrog/design-pattern-learning/tree/master/迭代器模式
【大话设计模式】https://book.douban.com/subject/2334288/
【极客时间】https://time.geekbang.org/column/intro/100039001
【迭代器模式】https://boilingfrog.github.io/2021/11/24/使用go实现迭代器模式/

————————
  • Iterator mode
    definition
    advantage
    shortcoming
    Scope of application
    code implementation
    reference resources
  • definition
  • advantage
  • shortcoming
  • Scope of application
  • code implementation
  • reference resources

Iterator mode

definition

Iterator design pattern, also known as cursor design pattern.

It provides a method to access the elements of an aggregate object sequentially, rather than exposing the internal representation of the object.

The aggregation object here is also called container aggregation object. In essence, it contains a group of objects in time, such as arrays, linked lists, trees, graphs and jump lists. The iterator mode splits the traversal operation of collection objects from the collection class and puts them into the iterator class, making their responsibilities more single.

A popular summary for iterator mode:

Sit on the assembly line for a day and sweep each package.

advantage

Advantages of iterators over for loops

1. The iterator pattern encapsulates the complex data structure inside the collection. Developers do not need to know how to traverse, but can directly use the iterator provided by the container;

2. The iterator mode separates the traversal operation of collection objects from the collection class and puts them into the iterator class, making their responsibilities more single;

3. The iterator pattern makes it easier to add new traversal algorithms and more in line with the opening and closing principle. In addition, because iterators are implemented from the same interface, it is easier to replace iterators in development based on interface rather than implementation programming.

shortcoming

Because the iterator pattern separates the responsibility of storing data and traversing data, adding a new aggregation class needs to add a new iterator class, and the number of classes increases in pairs, which increases the complexity of the system to a certain extent.

Scope of application

1. Accessing the contents of an aggregate object without exposing its internal representation;

2. You need to provide multiple traversal methods for aggregate objects;

3. Provide a unified interface for traversing different aggregation structures.

code implementation

Use the iterator to output the collection of names in the slice

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

type names []string

func (na names) NewIterator() *NameRepository {
	return &NameRepository{
		index: 0,
		names: na,
	}
}

type NameRepository struct {
	index int
	names names
}

func (nr *NameRepository) HasNext() bool {
	if nr.index < len(nr.names) {
		return true
	}
	return false
}

func (nr *NameRepository) Next() string {
	if nr.HasNext() {
		name := nr.names[nr.index]
		nr.index++
		return name
	}

	return ""
}

Test code

func TestIterator(t *testing.T) {
	names := names{
		"小明", "小豆", "小龙",
	}
	nameRepository := names.NewIterator()
	for nameRepository.HasNext() {
		t.Log(nameRepository.Next())
	}
}

reference resources

[code in text] https://github.com/boilingfrog/design-pattern-learning/tree/master/ Iterator mode
[big talk design mode] https://book.douban.com/subject/2334288/
[geek time] https://time.geekbang.org/column/intro/100039001
[iterator mode] https://boilingfrog.github.io/2021/11/24/ Implementing iterator pattern with go/