目录

GO语言实现设计模式-责任链模式

设计模式是针对软件设计中常见问题的工具箱,它能指导你如何使用面向对象的设计原则来解决各种问题,提高开发效率,降低开发成本.

责任链简介

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。

该模式允许多个对象来对请求进行处理,而无需让发送者类与具体接收者类相耦合。链可在运行时由遵循标准处理者接口的任意处理者动态生成。

一般意义上的责任链模式是说,请求在链上流转时任何一个满足条件的节点处理完请求后就会停止流转并返回,不过还可以根据不同的业务情况做一些改进:

  • 请求可以流经处理链的所有节点,不同节点会对请求做不同职责的处理。

  • 可以通过上下文参数保存请求对象及上游节点的处理结果,供下游节点依赖,并进一步处理。

  • 处理链可支持节点的异步处理,通过实现特定接口判断,是否需要异步处理。

  • 责任链对于请求处理节点可以设置停止标志位,不是异常,是一种满足业务流转的中断。

  • 责任链的拼接方式存在两种,一种是节点遍历,一个节点一个节点顺序执行;另一种是节点嵌套,内层节点嵌入在外层节点执行逻辑中,类似递归,或者“回”行结构。

  • 责任链的节点嵌套拼接方式多被称为拦截器链或者过滤器链,更易于实现业务流程的切面,比如监控业务执行时长,日志输出,权限校验等。

示例

本示例模拟实现机场登机过程

  • 第一步办理登机牌

  • 第二步如果有行李,就办理托运

  • 第三步核实身份

  • 第四步安全检查

  • 第五步完成登机

其中行李托运是可选的,其他步骤必选,必选步骤有任何不满足就终止登机。

旅客对象作为请求参数上下文,每个步骤会根据旅客对象状态判断是否处理或流转下一个节点。

登机过程

新建main.go,内容如下:

  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
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package main

import "fmt"

// BoardingProcessor 登机过程中,各节点统一处理接口
type BoardingProcessor interface {
  SetNextProcessor(processor BoardingProcessor)
  ProcessFor(passenger *Passenger)
}

// Passenger 旅客
type Passenger struct {
  name                  string // 姓名
  hasBoardingPass       bool   // 是否办理登机牌
  hasLuggage            bool   // 是否有行李需要托运
  isPassIdentityCheck   bool   // 是否通过身份校验
  isPassSecurityCheck   bool   // 是否通过安检
  isCompleteForBoarding bool   // 是否完成登机
}

// baseBoardingProcessor 登机流程处理器基类
type baseBoardingProcessor struct {
  // nextProcessor 下一个登机处理流程
  nextProcessor BoardingProcessor
}

// SetNextProcessor 基类中统一实现设置下一个处理器方法
func (b *baseBoardingProcessor) SetNextProcessor(processor BoardingProcessor) {
  b.nextProcessor = processor
}

// ProcessFor 基类中统一实现下一个处理器流转
func (b *baseBoardingProcessor) ProcessFor(passenger *Passenger) {
  if b.nextProcessor != nil {
    b.nextProcessor.ProcessFor(passenger)
  }
}

// boardingPassProcessor 办理登机牌处理器
type boardingPassProcessor struct {
  baseBoardingProcessor // 引用基类
}

func (b *boardingPassProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("为旅客%s办理登机牌;\n", passenger.name)
    passenger.hasBoardingPass = true
  }
  // 成功办理登机牌后,进入下一个流程处理
  b.baseBoardingProcessor.ProcessFor(passenger)
}

// luggageCheckInProcessor 托运行李处理器
type luggageCheckInProcessor struct {
  baseBoardingProcessor
}

func (l *luggageCheckInProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("旅客%s未办理登机牌,不能托运行李;\n", passenger.name)
    return
  }
  if passenger.hasLuggage {
    fmt.Printf("为旅客%s办理行李托运;\n", passenger.name)
  }
  l.baseBoardingProcessor.ProcessFor(passenger)
}

// identityCheckProcessor 校验身份处理器
type identityCheckProcessor struct {
  baseBoardingProcessor
}

func (i *identityCheckProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("旅客%s未办理登机牌,不能办理身份校验;\n", passenger.name)
    return
  }
  if !passenger.isPassIdentityCheck {
    fmt.Printf("为旅客%s核实身份信息;\n", passenger.name)
    passenger.isPassIdentityCheck = true
  }
  i.baseBoardingProcessor.ProcessFor(passenger)
}

// securityCheckProcessor 安检处理器
type securityCheckProcessor struct {
  baseBoardingProcessor
}

func (s *securityCheckProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("旅客%s未办理登机牌,不能进行安检;\n", passenger.name)
    return
  }
  if !passenger.isPassSecurityCheck {
    fmt.Printf("为旅客%s进行安检;\n", passenger.name)
    passenger.isPassSecurityCheck = true
  }
  s.baseBoardingProcessor.ProcessFor(passenger)
}

// completeBoardingProcessor 完成登机处理器
type completeBoardingProcessor struct {
  baseBoardingProcessor
}

func (c *completeBoardingProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass ||
    !passenger.isPassIdentityCheck ||
    !passenger.isPassSecurityCheck {
    fmt.Printf("旅客%s登机检查过程未完成,不能登机;\n", passenger.name)
    return
  }
  passenger.isCompleteForBoarding = true
  fmt.Printf("旅客%s成功登机;\n", passenger.name)
}

测试程序

 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
package main

import "testing"

func TestChainOfResponsibility(t *testing.T) {
  boardingProcessor := BuildBoardingProcessorChain()
  passenger := &Passenger{
    name:                  "李四",
    hasBoardingPass:       false,
    hasLuggage:            true,
    isPassIdentityCheck:   false,
    isPassSecurityCheck:   false,
    isCompleteForBoarding: false,
  }
  boardingProcessor.ProcessFor(passenger)
}

// BuildBoardingProcessorChain 构建登机流程处理链
func BuildBoardingProcessorChain() BoardingProcessor {
  completeBoardingNode := &completeBoardingProcessor{}

  securityCheckNode := &securityCheckProcessor{}
  securityCheckNode.SetNextProcessor(completeBoardingNode)

  identityCheckNode := &identityCheckProcessor{}
  identityCheckNode.SetNextProcessor(securityCheckNode)

  luggageCheckInNode := &luggageCheckInProcessor{}
  luggageCheckInNode.SetNextProcessor(identityCheckNode)

  boardingPassNode := &boardingPassProcessor{}
  boardingPassNode.SetNextProcessor(luggageCheckInNode)
  return boardingPassNode
}

编码完成,执行go test -v -run TestChainOfResponsibility,控制台输出如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ go test -v -run TestChainOfResponsibility
=== RUN   TestChainOfResponsibility
为旅客李四办理登机牌;
为旅客李四办理行李托运;
为旅客李四核实身份信息;
为旅客李四进行安检;
旅客李四成功登机;
--- PASS: TestChainOfResponsibility (0.00s)
PASS
ok
信息
至此,责任链模式 介绍完毕。