Go编程模式 - 8-装饰、管道和访问者模式

简介: 装饰、管道和访问者模式的使用频率不高,但在特定场景下会显得很酷

目录

今天,我会抛开官方的定义,简单介绍一下三种设计模式。

后续会有介绍Go语言设计模式Design Patterns的系列,会更具理论性。

Decoration

代码实例

func decorator(f func(s string)) func(s string) {
   
    return func(s string) {
   
        fmt.Println("Started")
        f(s)
        fmt.Println("Done")
    }
}

一句话解释:在函数f前后,添加装饰性的功能函数,但不改变函数本身的行为

这种设计模式,对一些被高频率调用的代码非常有用:

  1. HTTP Server被调用的handler
  2. HTTP Client发送请求
  3. 对MySQL的操作

而装饰性的功能,常见的有:

  1. 打印相关的日志信息(Debug中非常有用!)
  2. 耗时相关的计算
  3. 监控埋点

Pipeline

代码示例

type HttpHandlerDecorator func(http.HandlerFunc) http.HandlerFunc
func Handler(h http.HandlerFunc, decors ...HttpHandlerDecorator) http.HandlerFunc {
   
    for i := range decors {
   
        d := decors[len(decors)-1-i] // iterate in reverse
        h = d(h)
    }
    return h
}

一句话解释:用不定参数的特性,将入参中的函数,逐个应用到对象上

看到这里,如果你能想起之前 Functional Option 那篇,会发现有这块的影子。

主要应用于: 有多种可选择的配置(对应Field)或处理(对应方法)的复杂对象。

耗子叔在后面又增加了一些用Goroutine+Channel的方式,其实就是讲Channel作为一个管道的承载体。

Visitor

关于访问者设计者模式,我之前在Kubernetes源码分析中专门分析了源码。今天,我们也简单地过一下。

// 定义访问的函数类型
type VisitorFunc func(*Info, error) error

// Visitor接口设计
type Visitor interface {
   
    Visit(VisitorFunc) error
}

// 资源对象
type Info struct {
   
    Namespace   string
    Name        string
    OtherThings string
}

// 将Visitor函数应用到资源对象上
func (info *Info) Visit(fn VisitorFunc) error {
   
    return fn(info, nil)
}

然后看其中一个实现:NameVisitor,其余的也类似,这样就能注入对应的Visitor

type NameVisitor struct {
   
    visitor Visitor
}

func (v NameVisitor) Visit(fn VisitorFunc) error {
   
    return v.visitor.Visit(func(info *Info, err error) error {
   
        // 这里是运行入参中的VisitorFunc,这一块的逻辑有点像pipeline
        err = fn(info, err)
        // NameVisitor自己实现的Visit逻辑
        return err
    })
}

当然,Kubernetes中的Visitor还有进一步的封装,包括遇到错误时的处理,这里不细讲,有兴趣的朋友可以看看我对那一篇的分析。

Visitor模式最大的优点就是 解耦了数据和程序。回头看Kubernetes的Visitor应用场景,主要是从各种输入源中解析出资源Info。这个过程中Info是数据,各类解析方法是资源。

所以,我认为Visitor模式比较适合的是:目标数据明确,但获取数据的方法多样且复杂。但由于多层Visitor调用复杂,建议大家可以在外面再简单地封一层,提供常用的几种Visitor组合后的接口,供使用方调用。

目录
相关文章
|
6月前
|
存储 缓存 Go
Go语言并发编程(三)——初窥管道
Go语言并发编程(三)——初窥管道
|
4月前
|
设计模式 算法 Go
|
6月前
|
Linux Go 索引
go语言并发编程(四) ——再探管道
go语言并发编程(四) ——再探管道
|
7月前
|
设计模式 Go
[设计模式 Go实现] 行为型~访问者模式
[设计模式 Go实现] 行为型~访问者模式
|
Go
Go的管道进阶操作
除了基本的管道操作,还有一些稍微高级点的操作。
81 0
|
Kubernetes Shell Go
Go编程模式 - 7-代码生成
良好的命名能体现出其价值。尤其是在错误码的处理上,无需再去查询错误码对应的错误内容,直接可以通过命名了解。
68 0
|
SQL 分布式计算 Go
Go编程模式 - 6-映射、归约与过滤
但是,我不建议大家在实际项目中直接使用这一块代码,毕竟其中大量的反射操作是比较耗时的,尤其是在延迟非常敏感的web服务器中。 如果我们多花点时间、直接编写指定类型的代码,那么就能在编译期发现错误,运行时也可以跳过反射的耗时。
58 0
|
Go
Go编程模式 - 5.函数式选项
编程的一大重点,就是要 `分离变化点和不变点`。这里,我们可以将必填项认为是不变点,而非必填则是变化点。
40 0
|
Go
Go编程模式 - 4.错误处理
如何Wrap Error,在多人协同开发、多模块开发过程中,很难统一。而一旦不统一,容易出现示例中的过度Unwrap的情况。
37 0
|
Go
Go编程模式 - 3.继承与嵌入
业务逻辑依赖控制逻辑,才能保证在复杂业务逻辑变化场景下,代码更健壮!
53 0