文章目录
- [十五、chain of responsibility 责任链](#十五、chain of responsibility 责任链)
-
- [15.1 oa 审批系统](#15.1 oa 审批系统)
-
- [15.1.1 oa_test.go](#15.1.1 oa_test.go)
- [15.1.2 oa.go](#15.1.2 oa.go)
- [15.1.3 step.go](#15.1.3 step.go)
- [15.2 敏感词过滤器](#15.2 敏感词过滤器)
-
- [15.2.1 filter_test.go](#15.2.1 filter_test.go)
- [15.2.2 filter.go](#15.2.2 filter.go)
十五、chain of responsibility 责任链
https://refactoringguru.cn/design-patterns/chain-of-responsibility
如果需按顺序, 执行一系列步骤, 可用责任链.
链条上的每个步骤, 都持有下一个步骤的引用, 当自身步骤执行完毕后, 执行下一个步骤.
在运行时, client 也可以主动编辑 链的顺序.
核心是, 各步骤都实现相同的接口.
15.1 oa 审批系统
公司有流程申请系统, 员工的申请, 需要逐层审批. 是典型的链式.
基层员工, 先 HR 审批, 再 TL 审批, 再 BOSS 审批
bash
├── oa.go
├── oa_test.go
├── readme.md
└── step.go
15.1.1 oa_test.go
go
package _51oa
import (
"fmt"
"testing"
)
/*
=== RUN TestOAStep
流程开始
[hrStep] 开始审批
开始处理
[tlStep] 开始审批
开始处理
[bossStep] 开始审批
开始处理
流程结束
--- PASS: TestOAStep (0.00s)
PASS
*/
func TestOAStep(t *testing.T) {
o := NewOA()
fmt.Println("流程开始")
o.approval()
fmt.Println("流程结束")
}
15.1.2 oa.go
go
package _51oa
type oa struct {
firstStep iStep
}
func NewOA() *oa {
hr := &hrStep{}
tl := &tlStep{}
boss := &bossStep{}
hr.setNext(tl)
tl.setNext(boss)
boss.setNext(nil)
return &oa{
firstStep: hr,
}
}
// 审批
func (o *oa) approval() {
o.firstStep.handle()
}
15.1.3 step.go
go
package _51oa
import (
"fmt"
)
// iStep 是步骤
type iStep interface {
// 处理
handle()
// 设置下一步骤
setNext(iStep)
}
// 基本步骤, 是基类, 实现通用方法
type baseStep struct {
// 链上的下一节点
next iStep
}
// 各具体实现, 可复用的方法
func (s *baseStep) handle() {
fmt.Println("开始处理")
if s.next != nil { // 本步骤执行结束后, 传递给下一步骤继续处理
s.next.handle()
}
}
// 各具体实现, 可复用的方法
func (s *baseStep) setNext(nxt iStep) {
s.next = nxt
}
// hr步骤
type hrStep struct {
baseStep
}
// 重写方法
func (s *hrStep) handle() {
fmt.Println("[hrStep] 开始审批")
s.baseStep.handle()
}
// tl步骤
type tlStep struct {
baseStep
}
func (s *tlStep) handle() {
fmt.Println("[tlStep] 开始审批")
s.baseStep.handle()
}
// boss步骤
type bossStep struct {
baseStep
}
func (s *bossStep) handle() {
fmt.Println("[bossStep] 开始审批")
s.baseStep.handle()
}
15.2 敏感词过滤器
如果希望做一个论坛, 由于法律, 广告等原因, 需要敏感词过滤, 如果含敏感词, 则帖子会被封禁
其实各 filter 构成了职责链
bash
├── filter.go
├── filter_test.go
└── readme.md
15.2.1 filter_test.go
go
package _52sensitive_word_filter
import (
"github.com/stretchr/testify/require"
"testing"
)
/*
=== RUN TestFilter
执行广告过滤
执行广告过滤
执行法律过滤
--- PASS: TestFilter (0.00s)
PASS
*/
func TestFilter(t *testing.T) {
chain := SensitiveWordFilterChain{}
chain.AddFilter(&AdFilter{})
ret := chain.Filter("abc")
require.True(t, ret)
chain.AddFilter(&PoliceFilter{})
ret = chain.Filter("abc")
require.True(t, ret)
}
15.2.2 filter.go
go
package _52sensitive_word_filter
import "fmt"
// SensitiveWordFilter 过滤器接口
type SensitiveWordFilter interface {
Filter(content string) bool
}
// SensitiveWordFilterChain 职责链
type SensitiveWordFilterChain struct {
filters []SensitiveWordFilter
}
func (c *SensitiveWordFilterChain) AddFilter(f SensitiveWordFilter) {
c.filters = append(c.filters, f)
}
func (c *SensitiveWordFilterChain) Filter(content string) bool {
for _, f := range c.filters {
f.Filter(content)
}
return true
}
// AdFilter 广告过滤器
type AdFilter struct{}
func (f *AdFilter) Filter(content string) bool {
fmt.Println("执行广告过滤")
return true
}
// PoliceFilter 法律过滤器
type PoliceFilter struct{}
func (f *PoliceFilter) Filter(content string) bool {
fmt.Println("执行法律过滤")
return true
}