Go设计模式-责任链

35 阅读2分钟

什么是责任链

责任链模式允许开发者将请求沿着链进行发送,直至其中一个处理者对象对其进行处理。 责任链模式可以将请求的发送者和接收者解耦

责任链模式允许多个处理者对象对请求进行处理,无须让发送者类与具体的接收者类相耦合

组成:

  • 处理者(handler): 声明所有具体处理者类的通用接口。该接口通常仅包含一个方法,用于处理请求,但有时还会包含一个用于设置下一个具体处理者对象的方法
  • 基础处理者(BaseHandler): 一个可选的类,开发者可以将所有处理者对象共用的样本代码放置在其中
  • 具体处理者(ConcreteHandler): 包含处理请求实际代码的类。每个具体处理者对象在接收到请求后,都必须决定是否进行处理,以及是否沿着链传递
  • 客户端(Client): 可以根据程序逻辑处理一次性或者动态的生成链,请求可以发送给链中的任意一个处理者对象,不一定是第一个处理者对象

代码实现

package main

import "fmt"

/*
定义处理者接口及其处理请求方法,确定客户端如何将请求传递给方法
*/

type Handler interface {
   SetNext(handler Handler)
   Handle(HandlerID int) int
}

// BaseHandler 基础处理者及其方法
type BaseHandler struct {
   name      string
   next      Handler
   HandlerID int
}

func NewBaseHandler(name string, next Handler, handlerID int) Handler {
   return &BaseHandler{
      name:      name,
      next:      next,
      HandlerID: handlerID,
   }
}

// Handle 处理指定的handleID
func (bh *BaseHandler) Handle(handleID int) int {
   if handleID < 4 {
      ch := &ConcreteHandler{}
      ch.Handle(handleID)
      if bh.next != nil {
         bh.next.Handle(handleID + 1)
      }
      return handleID + 1
   }
   return 0
}

// SetNext 设置下一个处理者对象
func (bh *BaseHandler) SetNext(handler Handler) {
   bh.next = handler
}

/*
定义具体处理者类和方法
*/

type ConcreteHandler struct {
}

func (ch *ConcreteHandler) Handle(handleID int) {
   fmt.Println("ConcreteHandler handleID:", handleID)
}

func main() {
   barry := NewBaseHandler("Barry", nil, 1)
   whj := NewBaseHandler("whj", barry, 2)
   handleID1 := barry.Handle(1)
   barry.SetNext(whj)
   fmt.Println(handleID1)
}

使用场景

  • 如果程序需要使用不同的方式处理不同种类的请求,并且请求类型和顺序预先未知,则可以使用责任链模式
  • 如果必须按照顺序执行多个具体处理者对象,则可以使用责任链模式
  • 如果所需的具体处理者对象及其顺序必须在运行时发生改变,则可以使用责任链模式

优缺点

优点

  • 可以控制处理的顺序
  • 符合单一职责
  • 符合开闭原则
  • 可以简化对象,对象不需要知道链结构

缺点

  • 部分请求可能未被处理
  • 可能造成循环调用
  • 不易调试
  • 增加维护成本(可能会出现重复代码)