在职责链模式中,多个处理器依次处理同一个请求。一个请求先经过 A
处理器处理,然后再把请求传递给 B
处理器,B
处理器处理完后再传递给 C
处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
在 GoF
的定义中,一旦某个处理器能处理这个请求,就不会继续将请求传递给后续的处理器了。当然,在实际的开发中,也存在对这个模式的变体,那就是请求不会中途终止传递,而是会被所有的处理器都处理一遍。
// 职责链模式:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。
package main
import "fmt"
type IHandler interface {
handle() bool
}
type HandlerA struct{}
func NewHandlerA() *HandlerA {
return &HandlerA{}
}
func (ha HandlerA) handle() bool {
handled := false
// ...
fmt.Println("handle A")
return handled
}
type HandlerB struct{}
func NewHandlerB() *HandlerB {
return &HandlerB{}
}
func (hb HandlerB) handle() bool {
handled := false
// ...
fmt.Println("handle B")
return handled
}
// 职责链
type HandlerChain struct {
handlers []IHandler
}
func NewHandlerChain() *HandlerChain {
return &HandlerChain{}
}
func (hc *HandlerChain) addHandler(handler IHandler) {
hc.handlers = append(hc.handlers, handler)
}
func (hc *HandlerChain) handle() {
for _, handler := range hc.handlers {
handled := handler.handle()
if handled {
break
}
}
}
举个实例应用的例子
// 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
}
单元测试
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 Context
的实现,其中 Next()
方法就是主要的执行方法,这里其实就是我们最上面说到的职责链模式的变体,因为它会在每一个处理函数中进行处理,而不是第一个接收到就停止了
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++
}
}