责任链模式在golang工程中的应用实践
背景
流程管理是多数软件开发过程中会遇到的场景。然而,由于流程引擎的部署、运维成本高,而部分软件=通常只需要个别流程管理。开发者经常需要实现业务的流程管理。以=员工离职为例,一般需要发起离职流程,离职流程需要经过多个领导审批。审批通过,继续下一个节点,审批不通过,需要流转到其他节点。
- 员工发起离职交接流程
- 直属领导确认
- 分管领导确认
- 人力确认
- 公司领导确认
责任链模式为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
责任链模式优点
- 降低对象之间的耦合度
- 可以快速增加新的处理类,处理的流程可以调整
- 避免了多重if-else
- 符合单一职责原则
责任链模式缺点
- 不能保证每个请求一定被处理
- 较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响
- 使用者需要正确设置职责链
具体实现
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
demo
以上述离职流程确认为例
handler类
type Handler interface {
process(ctx *DimissionContext) error
}
不同处理者
type DirectorHandler struct {
}
func (d *DirectorHandler) process(ctx *DimissionContext) error {
// 确认开发任务完成
// 确认测试任务完成
// 确认上线任务完成
// 确认代码合并完成
// 确认上线文档编写完成
// 确认上线文档审核完成
// 确认交接完成
return nil
}
type ManagerHandler struct {
}
func (m *ManagerHandler) process(ctx *DimissionContext) error {
// 确认离职人员工作交接
// 确认离职人员离职交接
// 确认离职人员离职面谈
return nil
}
type HRHandler struct {
}
func (h *HRHandler) process(ctx *DimissionContext) error {
// 确认离职人员离职面谈
// 确认离职人员离职交接
// 确认权限关闭
// 确认离职人员工作交接
return nil
}
type CEOHandler struct {
}
func (c *CEOHandler) process(ctx *DimissionContext) error {
// do something
return nil
}
处理节点编排类
type HandlerNode struct {
handler Handler
next *HandlerNode
}
func (h *HandlerNode) handle(ctx *DimissionContext) error {
err := h.handler.process(ctx)
if err != nil {
return err
}
if h.next != nil {
return h.next.handle(ctx)
}
return nil
}
func NewDimissionHandlerChain() *HandlerNode {
directorNode := &HandlerNode{handler: &DirectorHandler{}}
managerNode := &HandlerNode{handler: &ManagerHandler{}}
hrNode := &HandlerNode{handler: &HRHandler{}}
ceoNode := &HandlerNode{handler: &CEOHandler{}}
directorNode.next = managerNode
managerNode.next = hrNode
hrNode.next = ceoNode
return directorNode
}
上下文
type DimissionContext struct {
Name string
WorkingYears int
DepartmentName string
LastDay time.Time
}
client类 main.go
dimissionContext := &DimissionContext{
Name: "张三",
WorkingYears: 3,
DepartmentName: "技术部",
LastDay: time.Now().Add(time.Hour * 24 * 30),
}
handleNode := NewDimissionHandlerChain()
err := handleNode.handle(dimissionContext)
if err != nil {
panic(err)
}
总结
上述示例中,如果需要新增处理节点,或者修改处理逻辑,只需要添加或修改对应的handler方法。
针对需要驳回的流程等,可以添加中介节点,负责协调各节点的协调。这就不单是责任链模式可以完成设计的,需要引入其他设计模式综合考虑。