综合题

本内容选自 k8s (opens new window)

k8s visitor + 修饰器 + pipeline

这种写法,以 k8s 的 visitor 作为主要的实现方法,修饰器和 pipeline 作为辅助的实现手法

首先我们实现这段代码的目的是为了将数据结构和算法分离,并且,我们希望每段的算法处理数据结构的一部分。

// 行为
type visitorFunc func(*info, error) error
// 抽象层
type Visitor interface {
	Visit(visitorFunc) error
}
// 数据
type info struct {
	name string
	year int
	addr string
}

func (i *info) Visit(v visitorFunc) error {
	return v(i, nil)
}

我们基础部分已经写好了,这样就具备了基本的 visitor 的模式,接下来我们来写算法的实现

// 多态
type OneDeal struct {
	visitor Visitor
}

func (o OneDeal) Visit(v visitorFunc) error {
	return o.visitor.Visit(func(i *info, err error) error {
		e := v(i, err)
		fmt.Println("one deal", i.name)
		return e
	})
}

type twoDeal struct {
	visitor Visitor
}

func (o twoDeal) Visit(v visitorFunc) error {
	return o.visitor.Visit(func(i *info, err error) error {
		e := v(i, err)
		fmt.Println("two deal", i.addr, i.year)
		return e
	})
}

当算法搞定以后,我们在 main 调用一下:

func main() {
	o := &info{}
	var v Visitor = o
	v = OneDeal{v}
	v = twoDeal{v}
	l := func(i *info, err error) error {
		i.name = "liu"
		i.year = 2020
		i.addr = "beijing"
		return nil
	}
	v.Visit(l)
}

可以看到,visitor,pipline,以及修饰器的模式都运用了

  • visitor:上面一个 type func,下面的 interface,连在一起就是 visitor 模式
  • pipline:可以看到 visitor 的变量在不停的传递,然后调用的时候肯定会一直的调用不同的 visit func 函数,这就是 pipline
  • 修饰器:不同的 function,在不停的增加内容,并且输出的还是这个 function,这就是修饰器模式

可以看到,这个模式下,visitor 是主要的模式,其他的模式都是因这个模式而附带的效果,所以也可以说,visitor 自带 pipline 和修饰器模式,所以这种写法就单单的只是 visitor 而已。

接下来,我们将修饰器模式作为主要的模式,另外加上 visitor 和 pipline

修饰器 + k8s visitor + pipeline

同样的我们需要先构造一个 visitor 系统


type VisitorFunc func(*Info, error) error

type Visitor interface {
	Visit(VisitorFunc) error
}
type Info struct {
	name string
	year int
	addr string
}

func (i *Info) Visit(v VisitorFunc) error {
	return v(i, nil)
}

接下来我们创建一个修饰器系统

type VisitorBox struct {
	visitor     Visitor // 行为
	visitorFucs []VisitorFunc // 代表数据的桥梁
}

func NewVisitorBox(v Visitor, fn ...VisitorFunc) Visitor {
	if len(fn) == 0 {
		return v
	}
	return VisitorBox{visitorFucs: fn, visitor: v}
}
func (vi VisitorBox) Visit(v VisitorFunc) error {
	return vi.visitor.Visit(func(i *Info, e error) error {
		if e != nil {
			return e
		}

		if err := v(i, nil); err != nil {
			return err
		}

		for k := range vi.visitorFucs {
			if err := vi.visitorFucs[k](i, nil); err != nil {
				return err
			}
		}
		return nil

	})
}

接下来让我们调用一下

func main() {

	loadFile := func(info *Info, err error) error {
		info.name = "li"
		info.year = 10
		info.addr = "bj"
		return nil
	}
	func1 := func(info *Info, err error) error {
		fmt.Println(info.name)
		return nil
	}
	func2 := func(info *Info, err error) error {
		fmt.Println(info.year)
		return nil
	}
	func3 := func(info *Info, err error) error {
		fmt.Println(info.addr)
		return nil
	}

	info := &Info{}
	var v Visitor = info
	v = NewVisitorBox(v, func1, func2, func3)
	v.Visit(loadFile)
}

这种写法跟上面的写法改变之处在于创建了一个修饰器的 struct,并且装在了一个 pipline 的切片,然后我们就不用依次调用不同的算法结构体了,我们只需要在 new box 的时候将要执行的函数放入进去即可。