【Go-设计模式】迭代器模式 详解

shadowLogo

概念:

迭代器模式(Iterator Pattern)是常用的设计模式,属于 行为型模式

当 客户端 要 遍历这些集合元素 的时候,就需要使用 多种遍历方式,而且还会 暴露元素的内部结构,可以考虑使用迭代器模式解决

迭代器模式,提供一种 遍历集合元素统一接口,用 一致的方法 遍历集合元素,不需要知道 集合对象的 底层表示,即:不暴露其内部的结构

可以使用迭代器模式使遍历同时 应用迭代策略,如 请求新对象过滤处理对象 等。

kindle


UML:

uml

  • Iterator
    迭代器接口,供客户端 遍历集合 使用
  • ConcreteIterator
    具体的迭代器类,迭代集合的 具体实现
  • Aggregate
    统一的聚合接口, 将 客户端具体聚合 进行 解耦
  • ConcreteAggreage
    具体的聚合持有对象集合, 并提供 一个方法,返回 一个迭代器, 该迭代器可以 正确遍历集合

示例:

迭代器 功能接口:

type Iterator interface {
	HashNext() bool
	Next() interface{}
	Remove()
}

具体的迭代器类:

具体的迭代器类1:

type ConcreteIterator struct {
	eleList []string
	offset  int
}

func (this *ConcreteIterator) HashNext() bool {
	if this.offset < len(this.eleList) {
		return true
	}
	return false
}

func (this *ConcreteIterator) Next() interface{} {
	element := this.eleList[this.offset]
	this.offset += 1
	return element
}

func (this *ConcreteIterator) Remove() {
	index := copy(this.eleList[this.offset:], this.eleList[this.offset+1:])
	this.eleList = this.eleList[:this.offset+index]
}

func NewConcreteIterator(eleList []string) *ConcreteIterator {
	return &ConcreteIterator{
		eleList: eleList,
	}
}

具体的迭代器类2:

type ConcreteIterator2 struct {
	eleMap map[int64]string
	key    int64
}

func (this *ConcreteIterator2) HashNext() bool {
	if this.key < int64(len(this.eleMap)) {
		return true
	}
	return false
}

func (this *ConcreteIterator2) Next() interface{} {
	element := this.eleMap[this.key]
	this.key += 1
	return element
}

func (this *ConcreteIterator2) Remove() {
	delete(this.eleMap, this.key)
}

func NewConcreteIterator2(eleMap map[int64]string) *ConcreteIterator2 {
	return &ConcreteIterator2{
		eleMap: eleMap,
	}
}

聚合接口:

type Aggregate interface {
	Iterator() Iterator
}

具体的聚合类

具体的聚合类1:

type ConcreteAggregate struct {
	eleList []string
}

func (this *ConcreteAggregate) Iterator() Iterator {
	return NewConcreteIterator(this.eleList)
}

func (this *ConcreteAggregate) AddElement(info string) {
	this.eleList = append(this.eleList, info)
}

func NewConcreteAggregate() ConcreteAggregate {
	return ConcreteAggregate{
		eleList: []string{},
	}
}

具体的聚合类2:

type ConcreteAggregate2 struct {
	eleMap map[int64]string
}

func (this *ConcreteAggregate2) Iterator() Iterator {
	return NewConcreteIterator2(this.eleMap)
}

func (this *ConcreteAggregate2) AddKv(key int64, value string) {
	this.eleMap[key] = value
}

func NewConcreteAggregate2() ConcreteAggregate2 {
	return ConcreteAggregate2{
		eleMap: map[int64]string{},
	}
}

测试:

package main

import (
	"DemoProject/design/base23/iterator" // 根据自己的项目路径定制
	"fmt"
)

func main() {
	// iterator

	// ============== type1 ==================
	aggregate1 := iterator.NewConcreteAggregate1()

	aggregate1.AddElement("youzg")
	aggregate1.AddElement("is")
	aggregate1.AddElement("a")
	aggregate1.AddElement("good")
	aggregate1.AddElement("man")
	aggregate1.AddElement("!")

	iterator1 := aggregate1.Iterator()

	iterator1.Remove()

	for iterator1.HashNext() {
		fmt.Println(iterator1.Next())
	}

	// ============== type2 ==================
	aggregate2 := iterator.NewConcreteAggregate2()

	aggregate2.AddKv(0, "and")
	aggregate2.AddKv(1, "he")
	aggregate2.AddKv(2, "is")
	aggregate2.AddKv(3, "so")
	aggregate2.AddKv(4, "cool")
	aggregate2.AddKv(5, "!")

	iterator2 := aggregate2.Iterator()

	iterator2.Remove()

	for iterator2.HashNext() {
		fmt.Println(iterator2.Next())
	}
}

个人总结,就是封装集合类的操作接口,
使得不管是什么 数据结构,都用的是 同一套SDK 去操作


注意事项:

优点:

提供一个 统一的方法 遍历对象,Client 不用再考虑 聚合的类型,使用 一种方法 就可以 遍历对象

隐藏了 聚合的内部结构,客户端要 遍历聚合 的时候只能 取到迭代器,而 不会知道 聚合 的 具体组成

提供了一种 设计思想,就是 一个类 应该 只有一个引起变化的原因单一责任原则
聚合类 中,我们把 迭代器 分开,就是要把 管理对象集合遍历对象集合责任 分开,
这样一来 集合改变 的话,只影响到 聚合对象;而如果 遍历方式改变 的话,只影响到了 迭代器

当要 展示一组相似对象,或者 遍历一组相同对象时, 适合使用 迭代器模式

缺点:

每个聚合对象 都要 一个迭代器,会生成 多个迭代器不方便类之间的管理

posted @ 2021-12-15 09:13  在下右转,有何贵干  阅读(157)  评论(0)    收藏  举报