Go设计模式16-职责链模式(Gin的中间件实现)

注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用

笔记

代码实现

首先我们看一下一个简单的实现模板,然后我们再看看实际上我们常用 web 框架 gin 当中是如何处理请求的

Code

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Package chain 职责链模式
// 🌰 假设我们现在有个校园论坛,由于社区规章制度、广告、法律法规的原因需要对用户的发言进行敏感词过滤
// 如果被判定为敏感词,那么这篇帖子将会被封禁
package chain

// SensitiveWordFilter 敏感词过滤器,判定是否是敏感词
type SensitiveWordFilter interface {
Filter(content string) bool
}

// SensitiveWordFilterChain 职责链
type SensitiveWordFilterChain struct {
filters []SensitiveWordFilter
}

// AddFilter 添加一个过滤器
func (c *SensitiveWordFilterChain) AddFilter(filter SensitiveWordFilter) {
c.filters = append(c.filters, filter)
}

// Filter 执行过滤
func (c *SensitiveWordFilterChain) Filter(content string) bool {
for _, filter := range c.filters {
// 如果发现敏感直接返回结果
if filter.Filter(content) {
return true
}
}
return false
}

// AdSensitiveWordFilter 广告
type AdSensitiveWordFilter struct{}

// Filter 实现过滤算法
func (f *AdSensitiveWordFilter) Filter(content string) bool {
// TODO: 实现算法
return false
}

// PoliticalWordFilter 政治敏感
type PoliticalWordFilter struct{}

// Filter 实现过滤算法
func (f *PoliticalWordFilter) Filter(content string) bool {
// TODO: 实现算法
return true
}

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package chain

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestSensitiveWordFilterChain_Filter(t *testing.T) {
chain := &SensitiveWordFilterChain{}
chain.AddFilter(&AdSensitiveWordFilter{})
assert.Equal(t, false, chain.Filter("test"))

chain.AddFilter(&PoliticalWordFilter{})
assert.Equal(t, true, chain.Filter("test"))
}

Gin 的中间件实现

我们直接看一下 gin Context  的实现,其中 Next()  方法就是主要的执行方法,这里其实就是我们最上面说到的职责链模式的变体,因为它会在每一个处理函数中进行处理,而不是第一个接收到就停止了

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 Context struct {
// ...

// handlers 是一个包含执行函数的数组
// type HandlersChain []HandlerFunc
handlers HandlersChain
// index 表示当前执行到哪个位置了
index int8

// ...
}

// Next 会按照顺序将一个个中间件执行完毕
// 并且 Next 也可以在中间件中进行调用,达到请求前以及请求后的处理
// Next should be used only inside middleware.
// It executes the pending handlers in the chain inside the calling handler.
// See example in GitHub.
func (c *Context) Next() {
c.index++
for c.index < int8(len(c.handlers)) {
c.handlers[c.index](c)
c.index++
}
}

关注我获取更新

wechat
知乎
github

猜你喜欢


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处,禁止全文转载