概念
责任链模式(Chain of Responsibility Pattern):
为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解其模式,而不是其具体实现。责任链模式的独到之处是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。
具体实现
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
模式的场景和优缺点
使用场景
在处理消息的时候以过滤很多道
优点
- 降低耦合度。它将请求的发送者和接收者解耦
- 简化了对象。使得对象不需要知道链的结构
- 增强给对象指派职责的灵活性
- 通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任
- 增加新的请求处理类很方便
缺点
- 不能保证请求一定被接收
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用
- 可能不容易观察运行时的特征,有碍于除错
代码实现
package main
import (
"fmt"
)
// Manager 定义接口
type Manager interface {
HaveRight(money int) bool
HandleFeeRequest(name string, money int) bool
}
// ******RequestChain 职责链, 每一个责任链都要生成这个职责链******
// successor 继承者
type RequestChain struct {
Manager
successor *RequestChain
}
// SetSuccessor 设置处理者
func (r *RequestChain) SetSuccessor(m *RequestChain) {
r.successor = m
}
// HandleFeeRequest 调用链路会调用处理者
func (r *RequestChain) HandleFeeRequest(name string, money int) bool {
if r.Manager.HaveRight(money) {
return r.Manager.HandleFeeRequest(name, money)
}
if r.successor != nil {
return r.successor.HandleFeeRequest(name, money)
}
return false
}
// HaveRight ...
func (r *RequestChain) HaveRight(money int) bool {
return true
}
// ************************end**************************
// **********************项目管理责任链, 实现Manager接口********************
// ProjectManager ...
type ProjectManager struct {
Name string
}
// NewProjectManagerChain ...
func NewProjectManagerChain(name string) *RequestChain {
return &RequestChain{
Manager: &ProjectManager{Name: name},
}
}
// HaveRight ...
func (p *ProjectManager) HaveRight(money int) bool {
return money < 500
}
// HandleFeeRequest ...
func (p *ProjectManager) HandleFeeRequest(name string, money int) bool {
if name == "bob" {
fmt.Printf("Project manager permit %s %d fee request\n", name, money)
return true
}
fmt.Printf("Project manager don't permit %s %d fee request\n", name, money)
return false
}
// ************************end**************************
// **********************部门管理责任链, 实现Manager接口*******************
// DepManager ...
type DepManager struct {
Name string
}
// NewDepManagerChain ...
func NewDepManagerChain(name string) *RequestChain {
return &RequestChain{
Manager: &DepManager{Name: name},
}
}
// HaveRight ...
func (d *DepManager) HaveRight(money int) bool {
return money < 5000
}
// HandleFeeRequest ...
func (d *DepManager) HandleFeeRequest(name string, money int) bool {
fmt.Printf("my name:%s\n", d.Name)
if name == "tom" {
fmt.Printf("Dep manager permit %s %d fee request\n", name, money)
return true
}
fmt.Printf("Dep manager don't permit %s %d fee request\n", name, money)
return false
}
// ************************end**************************
// **********************通用责任链, 实现Manager接口*******************
// GeneralManager ...
type GeneralManager struct {
Name string
}
// NewGeneralManagerChain ...
func NewGeneralManagerChain(name string) *RequestChain {
return &RequestChain{
Manager: &GeneralManager{Name: name},
}
}
// HaveRight ...
func (g *GeneralManager) HaveRight(money int) bool {
return true
}
// HandleFeeRequest ...
func (g *GeneralManager) HandleFeeRequest(name string, money int) bool {
fmt.Printf("my name:%s\n", g.Name)
if name == "ada" {
fmt.Printf("General manager permit %s %d fee request\n", name, money)
return true
}
fmt.Printf("General manager don't permit %s %d fee request\n", name, money)
return false
}
// ************************end**************************
func main() {
c1 := NewProjectManagerChain("c1")
c2 := NewDepManagerChain("c2")
c3 := NewGeneralManagerChain("c3")
//c1 ---> c2 ----> c3
// 设置下一级职责链
c1.SetSuccessor(c2)
c2.SetSuccessor(c3)
var c Manager = c1
// RequestChain实现了Manager
// 以下的调用全部先调用RequestChain结构体的HandleFeeRequest函数
// 然后根据钱数, 依次往下调用。 projectManager -> depManager -> generalManager, 每一级调用前, 先调用RequestChain结构体的HandleFeeRequest函数
c.HandleFeeRequest("bob", 400)
c.HandleFeeRequest("tom", 1400)
c.HandleFeeRequest("ada", 10000)
c.HandleFeeRequest("floar", 400)
}