Go 设计模式-责任链模式

206 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

场景:

  • 在权限控制的场景中,我们经常会有多条件流程的判断,权限1满足,进行判断权限2,满足权限2,继续判断权限3,这样持续权限判断
  • 某系统的审批流程,组长、主管、经理、总经理,一层一层审批

普通方式实现

如果不使用设计模式时,每增加一个条件可能就需要增加权限判断,就会导致代码臃肿且维护性差。比如实现方式如下:

package pkg
​
type DealHandler interface {
  handler() bool
}
type ADeal struct {
  name string
}
func (adel *ADeal) handler() bool {
  println(adel.name + "A 审批")
  return true
}
type BDeal struct {
  name string
}
​
func (bdel *BDeal) handler() bool {
  println(bdel.name + "B 审批")
  return true
}
​
type CDeal struct {
  name string
}
​
func (cdel *CDeal) handler() bool {
  println(cdel.name + "c 审批")
  return true
}
​
func MainDeal() {
  AAA := ADeal{"我是A"}
  BBB := BDeal{"我是B"}
  CCC := CDeal{"我是C"}
  if AAA.handler() {
    if BBB.handler() {
      if CCC.handler() {
        println("都处理完成")
      }
    }
  }
}
​

你会发现,如果有100个审批的,你可能就会写100个 if 判断,整个代码就很冗余,如果需要去掉或者增加审批都会对代码改动很大,且有很大的风险。

优化改造

进一步优化下代码,我们可以通过每次审批时就开始判断下一次是否审批,互相关联形成一条链。

type IDuty interface {
  Handler()
}
​
type ADuty struct {
  Name  string
  BDuty *BDuty
}
​
func (aduty *ADuty) dispaly() bool {
  return true
}
​
func (aduty *ADuty) Handler() {
  if aduty.dispaly() {
    println("我是" + aduty.Name + "我完成工作")
    aduty.BDuty.Handler()
  }
}
​
type BDuty struct {
  Name  string
  CDuty *CDuty
}
​
func (bduty *BDuty) dispaly() bool {
  return true
}
​
func (bduty *BDuty) Handler() {
  if bduty.dispaly() {
    println("我是" + bduty.Name + "我完成工作")
    bduty.CDuty.Handler()
  }
}
​
type CDuty struct {
  Name  string
  DDuty *interface{}
}
​
func (cduty *CDuty) dispaly() bool {
  return true
}
​
func (cduty *CDuty) Handler() {
  if cduty.dispaly() {
    println("我是" + cduty.Name + "我完成工作")
    println("任务结束")
  }
}
​
func main() {
​
  cduty := pattern.CDuty{"cc", nil}
  bduty := pattern.BDuty{"BB", &cduty}
  aduty := pattern.ADuty{"AA", &bduty}
​
  aduty.Handler()
}

每个责任实例中包含下一个责任实例,再根据其 display 方法取判断是否进行下一个责任实例。但这样写法适合的场景是,每个责任都是明确的,形成一个固定的链接,代码扩展也不好。

责任链模式

type IDuty interface {
  SetNext(nextDuty IDuty) IDuty //设置下一个业务
  Do() // 自身的业务
  Handler() //执行
}
​
type DutyClass struct {
  Name string
  Next IDuty
}
​
func (aduty *DutyClass) Do() {
  if isDeal {
    // ---处理自身业务
   
  }
}
​
func (aduty *DutyClass) SetNext(nextDuty IDuty) IDuty {
  aduty.Name = ""
  aduty.Next = nextDuty
  return nextDuty
}
​
func (aduty *DutyClass) Handler() {
  println(aduty.Name + "处理")
 aduty.Next.Do()
  if aduty.Next != nil {
    aduty.Next.Handler()
  }
}
​
type ADuty struct {
  DutyClass
}
func (h *ADuty) Do() (err error) {
  fmt.Println("我是AAA处理...")
  return
}
​
type BDuty struct {
  DutyClass
}
func (h *BDuty) Do() (err error) {
  fmt.Println("我是 BBB 处理...")
  return
}
type CDuty struct {
  DutyClass
}
​
func (h *CDuty) Do() (err error) {
  fmt.Println("我是 CCC 处理...")
  return
}
​
func main(){
  firstDuty := &pattern.DutyClass{}
  firstDuty.SetNext(&pattern.ADuty{}).SetNext(&pattern.BDuty{}).SetNext(&pattern.CDuty{})
​
  firstDuty.Handler()
  println("执行结束")
}
  • 定义一个处理请求的接口 IDuty, 里面包含 包含抽象处理方法和一个后继连接。
  • 定义个具体的处理者,实现接口的方法,并且在 handler 方法中判断是否处理本次请求,不处理则转到后续处理者
  • 定义多个具体的处理对象,每个处理对象都是针对专门的业务划分

责任链的基本组成:

  • 抽象处理者(Handler)角色
  • 具体处理者(Concrete Handler)角色
  • 客户类(Client)角色

参考资料: