Skip to main content
  1. internet/

设计模式之迭代器、组合

·787 words·2 mins·

迭代器模式 #

迭代器模式用于封装遍历过程以达到隐藏内部实现细节的目的。

迭代器模式分为内部迭代器和外部迭代器两种。

内部迭代器 #

内部迭代器由迭代器本身来控制遍历。

type Student struct{}

type Students []Student

func (s Students) Iterator(fnc func(student Student)) {
	for _, student := range s {
		fnc(student)
	}
}

我们新定义了一个Students类型用来封装Student列表,并且提供了Iterator方法来实现遍历。

内部迭代器的有点就是实现简单、使用简单,缺点则是使用方不能控制遍历逻辑。

假设说我们新的处理Student的方法需要一个error返回值,这时候Iterator已经不能满足需求,需要新定义一个方法:

func (s Students) Iterator2(fnc func(student Student) error) error {
	for _, student := range s {
		if err := fnc(student); err != nil {
			return err
		}
	}
	return nil
}

也就是说,内部迭代器的扩展性不够好,且使用不够灵活。假如遍历过程中,fnc找到所需的student就不应该继续遍历其他student,那么我们又需要再写一个新的方法。

外部迭代器 #

外部迭代器将迭代的控制权提供给使用方,实现如下:

type Student struct{}

type Students struct{
	offset int
	data []Student
}

func (s *Students) HasNext() bool {
	return s.offset >= len(s.data)
}

func (s *Students) Next() Student {
	if !s.HasNext() {
		panic("index out of range")
	}
	stu := s.data[s.offset]
	s.offset++
	return stu
}

func example(students Students)  {
	for students.HasNext() {
		student := students.Next()
		fmt.Println(student)
	}
}

外部迭代器只会控制自己的数据,而不会控制遍历。 因此这种模式在使用时更加灵活。

组合模式 #

组合模式允许你将对象组合成树状结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合

假设我们有三级部门,每个层级的部门都有共同的处理方式,所以我们可以提供基础对象Dept,并组装成树状结构。

type Dept struct {
	name  string
	level int
	child []*Dept
}

func (d *Dept) Add(dept *Dept) {
	d.child = append(d.child, dept)
}

func (d *Dept) Print() {
	fmt.Printf("name: %s, level: %d", d.name, d.level)
}

func (d *Dept) Iterator(fnc func(dept *Dept)) {
	fnc(d)
	for _, v := range d.child {
		fnc(v)
	}
}

func example2() {
	// 一级部门
	dept1 := &Dept{
		name:  "root",
		level: 1,
		child: nil,
	}
	// 二级部门
	dept2 := &Dept{
		name:  "a",
		level: 2,
		child: nil,
	}
	dept3 := &Dept{
		name:  "b",
		level: 2,
		child: nil,
	}
	// 三级部门
	dept4 := &Dept{
		name:  "c",
		level: 3,
		child: nil,
	}
	dept1.Add(dept2)
	dept1.Add(dept3)
	dept2.Add(dept4)

	dept1.Iterator(func(dept *Dept) {
		dept.Print()
	})
}

总结 #

  1. 内部迭代器比外部迭代器使用简单、实现简单,但是更没有弹性。
  2. 组合模式就是将对象组合成树状结构,并提供统一的方法遍历与处理。