go 实现责任链模式
# 一、问题
- 业务扩张与缩减过程中,对应地就会有功能的增减,如果每次功能的增减都需要改动非常多的代码,就会导致代码逻辑不够清晰易懂,业务逻辑混乱的问题;
- 在实际开发中,将整个业务流程拆分不同的子流程,对应地每个代码块节点处理一个子流程,最后将这些代码块串起来执行,即可对应整个业务流程;
- 当该条业务有子流程增减时,只需要增减对应的代码块节点即可,这就是应用了责任链模式;
# 二、基本介绍
- 责任链模式是一种行为设计模式,用于将请求的发送者和接收者解耦,通过多个处理节点对请求的处理,将请求的传递与处理链条化;
- 在实际应用中,责任链模式常用于处理复杂的请求处理流程,使得请求能够沿着处理链依次传递,每个处理节点负责判断能否处理请求并进行处理或转发;
- 每个处理节点对应一个业务子流程,当业务子流程有增减时只需要对应的增减处理节点;
# 三、模式结构
- 责任链模式主要包含接口、子节点实现、数据类型、客户端四部分:
- 接口:定义处理请求数据的方法,通常包括具体的数据处理方法、责任链转移方法和子节点链接方法;
- 子节点实现:实现接口定义的方法,负责处理请求数据和节点转移;
- 数据类型:定义请求与返回的数据结构,各个节点从该结构中读取要处理的数据,以及写回处理后的数据;
- 客户端:创建并组装责任链,向责任链的起始点提交请求数据;
# 四、工作原理
- 请求提交:客户端创建请求数据并组装责任链,将请求数据提交给责任链的第一个处理者(即起始点);
- 处理判断:每个子节点处理者根据自身的业务逻辑判断是否能够处理该请求;如果可以处理,则处理请求并写回结果,遇到错误时可以提前返回;如果不能处理,则将请求传递给责任链中的下一个处理者;
- 责任链传递:请求沿着责任链依次传递,直到找到能够处理请求的处理者为止;
- 请求完成:当某个处理者成功处理请求后,责任链模式可以选择终止传递或继续传递给下一个处理者。
# 五、实例分析
# Handler 接口
Handler
是每个逻辑节点的接口,定义了三个方法,分别是:Execute(*Data) error
:接收请求数据,负责逻辑节点的执行与转移,即从前往后依次执行责任链上的每个节点,直至出错返回或是执行完毕;SetNext(Handler) Handler
:负责将某个节点链接到当前节点的后面,并返回后一个节点,保证能够依次链接器所有的逻辑节点;Do(*Data) error
:接收请求数据,真正的逻辑处理的部分,由具体的业务逻辑节点实现,在Execute
方法中被调用;
# 中间对象 Next
Next
结构体,是一个没有具体逻辑的抽象节点,它包含了Handler
接口的元素,用来存储下一个逻辑节点;Next
结构体实现了Handler
接口中的Execute
方法和SetNext
方法,但是没有实现Do
方法,所以其没有实现Handler
接口;- 其
SetNext
方法用于将下一个逻辑节点存储到 nextHandler 中,并且返回 nextHandler 的地址; - 其
Execute
方法会调用 nextHandler 的Do
方法:如果 nextHandler 为空,则说明达到末尾,直接返回;否则调用 nextHandler 的Do
方法,执行具体子节点的逻辑处理。如果子节点逻辑执行中失败了,则提前返回,不再执行后续节点;执行成功了,则进行逻辑节点的转移,继续执行下一个节点的逻辑处理; - 此时
Next
结构体可以理解为一个中间对象,其实现了Execute
和SetNext
方法,避免了在 A、B、C 中重复实现这两个方法,子节点只需要负责具体的逻辑处理,而不需要关注责任链的拼接与转移; Next
结构体没有实现Do
方法,不能在Execute
方法中直接调用自己的Do
方法,只能调用 nextHandler 的Do
方法,以下是一个错误的示例;
func (n *Next) Execute(data *Data) (err error) {
if n == nil {
return
}
if err = n.Do(data); err != nil {
return
}
return n.nextHandler.Execute(data)
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 子节点
- A、B、C 结构体就是处理具体逻辑的子节点,都是包含了
Next
匿名组合体的结构,其实现了Do
方法,而Next
实现了Execute
和 SetNext 方法,那么 A、B、C 就都实现了Handler
接口,可以被当作一个子节点,被链接到责任链上; Do
方法从Data
中接收传入的数据,同时也可以将结果写回Data
,处理中出现错误时,也可以提前返回;StartHandler
也是一个子节点,不过不处理任何逻辑,只是作为第一个Handler
向下转发请求;
// 责任链模式
package main
import "fmt"
type Handler interface {
Execute(*Data) error // 负责逻辑节点的执行与转移
SetNext(Handler) Handler // 负责串起各个逻辑节点
Do(*Data) error // 真正的逻辑处理的部分
}
type Next struct {
nextHandler Handler
}
func (n *Next) SetNext(handler Handler) Handler {
n.nextHandler = handler
return handler
}
func (n *Next) Execute(data *Data) (err error) {
if n.nextHandler == nil {
return
}
if err = n.nextHandler.Do(data); err != nil {
return
}
return n.nextHandler.Execute(data)
}
type A struct {
Next
}
func (m *A) Do(d *Data) (err error) {
if d.IsADone {
fmt.Println("A has been done")
return
}
fmt.Println("Deal A")
d.IsADone = true
return
}
type B struct {
Next
}
func (m *B) Do(d *Data) (err error) {
if d.IsBDone {
fmt.Println("B has been done")
return
}
fmt.Println("Deal B")
d.IsBDone = true
return
}
type C struct {
Next
}
func (m *C) Do(d *Data) (err error) {
if d.IsCDone {
fmt.Println("C has been done")
return
}
fmt.Println("Deal C")
d.IsCDone = true
return
}
// StartHandler 不做操作,作为第一个 Handler 向下转发请求
type StartHandler struct {
Next
}
// Do 空 Handler 的 Do
func (h *StartHandler) Do(d *Data) (err error) {
// 空 Handler 这里什么也不做,只是载体 do nothing...
fmt.Println("StartHandler do nothing")
return
}
type Data struct {
Name string
IsADone bool
IsBDone bool
IsCDone bool
}
func main() {
s := StartHandler{}
s.SetNext(&A{}).SetNext(&B{}).SetNext(&C{}).SetNext(&B{})
// 执行业务流程中的各个责任点
data := &Data{Name: "abc"}
if err := s.Execute(data); err != nil {
fmt.Println("Error:" + err.Error())
return
}
fmt.Println("Success")
}
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
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
# 六、结论
- 责任链模式通过将请求的发送者和接收者解耦,提供了一种灵活且可扩展的处理方式;它能够动态地组织和分配责任,使得系统更易于维护和扩展;
- 责任链模式的核心思想是「链式处理」,在处理复杂业务流程时特别有用,它不仅提高了系统的灵活性和可扩展性,同时也使得代码更加清晰和易于理解;
- 在实际应用中,责任链模式常用于处理请求的优先级排序、权限校验、日志记录等场景,为复杂系统的请求处理提供了一种有效的解决方案;
编辑 (opens new window)
上次更新: 2024/07/10, 18:56:22