聚焦目标
理解kubectl的核心实现之一:Visitor Design Pattern
访问者模式
目录
什么是访问者模式
kubectl中的Visitor
Visitor的链式处理
- 多个对象聚合为一个对象
- VisitorList
- EagerVisitorList
- 多个方法聚合为一个方法
- DecoratedVisitor
- ContinueOnErrorVisitor
- 将对象抽象为多个底层对象,逐个调用方法
- FlattenListVisitor
- FilteredVisitor
Visitor的各类实现
- StreamVisitor
- FileVisitor
- URLVisitor
- KustomizeVisitor
visitor design pattern
在设计模式中,访问者模式的定义为:
允许一个或者多个操作应用到对象上,解耦操作和对象本身
那么,对一个程序来说,具体的表现就是:
- 表面:某个对象执行了一个方法
- 内部:对象内部调用了多个方法,最后统一返回结果
举个例子,
- 表面:调用一个查询订单的接口
- 内部:先从
缓存
中查询,没查到再去热点数据库
查询,还没查到则去归档数据库
里查询
Visitor
我们来看看kubeadm中的访问者模式
的定义:
1 2 3 4 5 6
| type Visitor interface { Visit(VisitorFunc) error }
type VisitorFunc func(*Info, error) error
|
基本的数据结构很简单,但从当前的数据结构来看,有两个问题:
单个操作
可以直接调用Visit
方法,那多个操作
如何实现呢?
- 在应用
多个操作
时,如果出现了error,该退出还是继续应用下一个操作
呢?
Chained
VisitorList
封装多个Visitor为一个,出现错误就立刻中止并返回
1 2 3 4 5 6 7 8 9 10 11 12
| type VisitorList []Visitor
func (l VisitorList) Visit(fn VisitorFunc) error { for i := range l { if err := l[i].Visit(fn); err != nil { return err } } return nil }
|
EagerVisitorList
封装多个Visitor为一个,出现错误暂存下来,全部遍历完再聚合所有的错误并返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| type EagerVisitorList []Visitor
func (l EagerVisitorList) Visit(fn VisitorFunc) error { errs := []error(nil) for i := range l { if err := l[i].Visit(func(info *Info, err error) error { if err != nil { errs = append(errs, err) return nil } if err := fn(info, nil); err != nil { errs = append(errs, err) } return nil }); err != nil { errs = append(errs, err) } } return utilerrors.NewAggregate(errs) }
|
DecoratedVisitor
这里借鉴了装饰器的设计模式,将一个Visitor调用多个VisitorFunc方法,封装为调用一个VisitorFunc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| type DecoratedVisitor struct { visitor Visitor decorators []VisitorFunc }
func (v DecoratedVisitor) Visit(fn VisitorFunc) error { return v.visitor.Visit(func(info *Info, err error) error { if err != nil { return err } for i := range v.decorators { if err := v.decorators[i](info, nil); err != nil { return err } } return fn(info, nil) }) }
|
ContinueOnErrorVisitor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| type ContinueOnErrorVisitor struct { Visitor }
func (v ContinueOnErrorVisitor) Visit(fn VisitorFunc) error { errs := []error{} err := v.Visitor.Visit(func(info *Info, err error) error { if err != nil { errs = append(errs, err) return nil } if err := fn(info, nil); err != nil { errs = append(errs, err) } return nil }) if err != nil { errs = append(errs, err) } if len(errs) == 1 { return errs[0] } return utilerrors.NewAggregate(errs) }
|
FlattenListVisitor
将runtime.ObjectTyper解析成多个runtime.Object,再转换为多个Info,逐个调用VisitorFunc
1 2 3 4 5
| type FlattenListVisitor struct { visitor Visitor typer runtime.ObjectTyper mapper *mapper }
|
FilteredVisitor
对Info资源的检验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| type FilteredVisitor struct { visitor Visitor filters []FilterFunc }
func (v FilteredVisitor) Visit(fn VisitorFunc) error { return v.visitor.Visit(func(info *Info, err error) error { if err != nil { return err } for _, filter := range v.filters { ok, err := filter(info, nil) if err != nil { return err } if !ok { return nil } } return fn(info, nil) }) }
|
Implements
StreamVisitor
最基础的Visitor
1 2 3 4 5 6 7 8
| type StreamVisitor struct { io.Reader *mapper
Source string Schema ContentValidator }
|
FileVisitor
文件的访问,包括标准输入,底层调用StreamVisitor来访问
1 2 3 4 5
| type FileVisitor struct { Path string *StreamVisitor }
|
URLVisitor
HTTP用GET方法获取数据,底层也是复用StreamVisitor
1 2 3 4 5 6
| type URLVisitor struct { URL *url.URL *StreamVisitor HttpAttemptCount int }
|
KustomizeVisitor
自定义的Visitor,针对自定义的文件系统
1 2 3 4
| type KustomizeVisitor struct { Path string *StreamVisitor }
|
Github: https://github.com/Junedayday/code_reading
Blog: http://junes.tech/
Bilibili:https://space.bilibili.com/293775192
公众号:golangcoding