Go设计模式之迭代器模式

197 阅读3分钟

迭代器模式是Go中的一种行为型设计模式,它提供了一种用于遍历聚合对象中元素的设计方案。该模式将聚合对象和遍历器对象分离,使得聚合对象和遍历器对象能够独立地变化和演化。在这篇文章中,我们将讨论Go语言中的迭代器模式,了解迭代器模式的实现以及它的好处。

迭代器模式的定义

迭代器模式是指提供一种方法来访问聚合对象中的每个元素,而又不暴露该对象的内部表示,也可以自定义访问操作。

迭代器模式通常包含以下角色:

  1. 抽象聚合类:声明确定的方法用于创建迭代器对象,同时抽象聚合类中包含了迭代器需要的接口方法。
  2. 具体聚合类:实现抽象聚合类中声明的抽象方法,并返回一个合适的迭代器实例。
  3. 抽象迭代器类:定义访问和操作聚合对象元素的接口。
  4. 具体迭代器类:实现抽象迭代器类中定义的接口方法,完成对聚合对象元素的遍历。

代码演示

以下是一个迭代器模式的例子,假设我们有一个字符串列表,现在我们想要遍历该列表中的所有字符串,并输出它们的内容。

抽象聚合类:

type Container interface {
    GetIterator() Iterator
}

具体聚合类:

type MyContainer struct {
    list []string
}

func (c *MyContainer) GetIterator() Iterator {
    return &MyIterator{
        index: 0,
        list:  c.list,
    }
}

抽象迭代器类:

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

具体迭代器类:

type MyIterator struct {
    index int
    list  []string
}

func (i *MyIterator) HasNext() bool {
    return i.index < len(i.list)
}

func (i *MyIterator) Next() interface{} {
    if !i.HasNext() {
        return nil
    }
    value := i.list[i.index]
    i.index++
    return value
}

现在我们来看看如何使用上述类:

func main() {
   container := NewContainer([]string{"one", "two", "three", "four", "five"})
   iterator := container.GetIterator()
   for iterator.HasNext() {
      fmt.Println(iterator.Next().(string))
   }
}

输出:

one
two
three
four
five

在上面的例子中,我们首先实例化了一个MyContainer类,它要求我们传入一个字符串列表。然后我们通过调用MyContainer类的GetIterator方法来获取一个迭代器对象。最后,我们使用该迭代器对象来遍历并输出其包含的字符串列表。

总结

迭代器模式提供了一种遍历数据集合的通用方式,不需要知道内部的数据结构和算法,只需要实现一个通用的迭代器对象即可。该模式增加了可扩展性,并将迭代器逻辑与聚合对象逻辑进行了分离,使得聚合对象能够独立于迭代器对象演化,这是Go语言中迭代器模式的主要优点。通过使用迭代器模式,我们可以更加灵活地使用聚合对象,并且可以通过增加新的迭代器类来扩展其行为。

完整代码

package main

import "fmt"

type Container interface {
   GetIterator() Iterator
}

type MyContainer struct {
   list []string
}

func (c *MyContainer) GetIterator() Iterator {
   return &MyIterator{
      index: 0,
      list:  c.list,
   }
}

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

type MyIterator struct {
   index int
   list  []string
}

func (i *MyIterator) HasNext() bool {
   return i.index < len(i.list)
}

func (i *MyIterator) Next() interface{} {
   if !i.HasNext() {
      return nil
   }
   value := i.list[i.index]
   i.index++
   return value
}

func NewContainer(strList []string) Container {
   return &MyContainer{list: strList}
}

func main() {
   container := NewContainer([]string{"one", "two", "three", "four", "five"})
   iterator := container.GetIterator()
   for iterator.HasNext() {
      fmt.Println(iterator.Next().(string))
   }
}