【设计模式】15、chain of responsibility 责任链模式

文章目录

  • [十五、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
}
相关推荐
XX風1 小时前
设计模式的本质
设计模式
折哥的程序人生 · 物流技术专研11 小时前
第8篇:六大设计原则在工厂模式中的体现
java·设计模式·设计原则·工厂模式·编程进阶·扩充系列
咖啡八杯12 小时前
GoF设计模式——模板方法模式
java·后端·spring·设计模式
饼干哥哥1 天前
Openclaw已死?任何Agent都能用Cli实现AI自主运营跨境电商
设计模式·openai·ai编程
折哥的程序人生 · 物流技术专研1 天前
第4篇:抽象工厂模式——产品族一键创建
java·设计模式·抽象工厂模式·创建型模式·编程进阶·产品族·扩充系列
geovindu2 天前
go: Cascading Failures Pattern
开发语言·后端·设计模式·golang·反模式·级联失效反模式
端庄的战斗机2 天前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
饼干哥哥2 天前
我开发了一个「吃掉」别人Skill来升级的饕餮.Skill,现在免费开源
人工智能·设计模式·开源
CaffeinePro2 天前
什么是系统架构?架构师到底在做什么?
设计模式·架构