设计模式之迭代器、组合
Table of Contents
迭代器模式 #
迭代器模式用于封装遍历过程以达到隐藏内部实现细节的目的。
迭代器模式分为内部迭代器和外部迭代器两种。
内部迭代器 #
内部迭代器由迭代器本身来控制遍历。
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()
})
}
总结 #
- 内部迭代器比外部迭代器使用简单、实现简单,但是更没有弹性。
- 组合模式就是将对象组合成树状结构,并提供统一的方法遍历与处理。