This website requires JavaScript.

设计模式在 TypeScript 中的应用 - 责任链模式

2018.01.13 14:12字数 4050阅读 565喜欢 9评论 0

定义

使多个对象都有机会处理请求,从而避免请求的发送者与接受者的耦合关系,将这些对象连成一条链,并沿着这个对象传递请求,直到有一个对象处理它为止。

实现

假设有一个请假的例子,约定如下:

  • 请假 1 天时,需由部门副经理审批。
  • 请假 2 - 3 天时,需由部门经理审批。
  • 请假 4 - 5 天时,需有公司副总经理审批。
  • 请假 5 天以上时,需由公司总经理审批。

不使用责任链模式时

class LeaveRequestHandler {
  // 姓名
  private name: string
  // 天数
  private day: number
  // 原因
  private reason: string

  public constructor (name: string, day: number, reason: string) {
    this.name = name
    this.day = day
    this.reason = reason
  }

  // 发送请假请求
  public setRequest () {
    if (this.day <= 1) {
      this.handleViceManager()
    } else if (this.day < 3) {
      this.handleManager()
    } else if (this.day < 5) {
      this.handViceBoss ()
    } else {
      this.handleBoss()
    }
  }

  public handleViceManager () {
    console.log('部门副经理签字')
  }
  public handleManager () {
    console.log('部门经理签字')
  }
  public handViceBoss () {
    console.log('公司副经理签字')
  }
  public handleBoss () {
    console.log('公司经理签字')
  }
}

const leave = new LeaveRequestHandler('jack', 5, '请假')
leave.setRequest() // 公司经理签字

仔细分析,会出现以下问题:

  • LeaveRequestHandler 类比较庞大。审批方法都集中在一起,违反单一职责。
  • 审批流程固定,如果要修改,只能从源码处改。
  • 如果添加一个审批流程,或者调整审批的时间时,需对源码就行修改。

使用责任模式时

主要有三个身份:

  • 请求类
  • 抽象处理者
  • 实际处理者
// 请求类
class LeaveRequest {
  private name: string
  private day: number
  private reason: string

  constructor (name: string, day: number, reason: string) {
    this.name = name
    this.day = day
    this.reason = reason
  }

  public getName (): string {
    return this.name
  }
  public getDay (): number {
    return this.day
  }
  public getReason (): string {
    return this.reason
  }
}

// 抽象处理类
abstract class Approver {
  // 下一个审批者
  protected nextApprover: Approver

  // 审批者姓名
  protected name: string

  constructor (name: string) {
    this.name = name
  }

  //设置后继者 
  public setNextApprover (approver: Approver) {
    this.nextApprover = approver
  }

  // 抽象处理请求
  public abstract getRequest (leaveRequest: LeaveRequest): void
}

// 具体处理者,部门副经理
class ViceManager extends Approver {
  constructor (name: string) {
    super(name)
  }

  // 接受请求
  public getRequest (leaveRequest: LeaveRequest) {
    if (leaveRequest.getDay() <= 1) {
      console.log(`部门副经理:${this.name},批准请求`)
    } else {
      // 转发给后继者
      this.nextApprover.getRequest(leaveRequest)
    }
  }
}

// 具体处理者,部门经理
class Manager extends Approver {
  constructor (name: string) {
    super(name)
  }

  // 接受请求
  public getRequest (leaveRequest: LeaveRequest) {
    if (leaveRequest.getDay() <= 3) {
      console.log(`部门经理:${this.name},批准请求`)
    } else {
      // 转发给后继者
      this.nextApprover.getRequest(leaveRequest)
    }
  }
}

// 具体处理者,公司副经理
class ViceBoss extends Approver {
  constructor (name: string) {
    super(name)
  }

  // 接受请求
  public getRequest (leaveRequest: LeaveRequest) {
    if (leaveRequest.getDay() <= 5) {
      console.log(`公司副经理:${this.name},批准请求`)
    } else {
      // 转发给后继者
      this.nextApprover.getRequest(leaveRequest)
    }
  }
}

// 具体处理者,公司经理
class Boss extends Approver {
  constructor (name: string) {
    super(name)
  }

  // 接受请求
  public getRequest (leaveRequest: LeaveRequest) {
    console.log(`公司经理:${this.name},批准请求`)
  }
}

const Mary = new ViceManager('Mary')
const Jack = new Manager('Jack')
const Rose = new ViceBoss('Rose')
const Sweet = new Boss('Sweet')

// 创建指责链
Mary.setNextApprover(Jack)
Jack.setNextApprover(Rose)
Rose.setNextApprover(Sweet)

// 创建请求
const leave1 = new LeaveRequest('JkChao', 1, '病假')
Mary.getRequest(leave1)

const leave2 = new LeaveRequest('JkChao', 2, '病假')
Mary.getRequest(leave2)

const leave3 = new LeaveRequest('JkChao', 4, '病假')
Mary.getRequest(leave3)

const leave4 = new LeaveRequest('JkChao', 10, '病假')
Mary.getRequest(leave4)



>  部门副经理:Mary,批准请求
   部门经理:Jack,批准请求
   公司副经理:Rose,批准请求
   公司经理:Sweet,批准请求

使用场景

  • 多个对象可以处理同一请求,具体哪个对象处理,根据设定的条件。
  • 不明确接受者,向多个对象提交请求时。

优缺点

优点:

  • 无须知道哪个对象处理请求,降低耦合度。
  • 请求处理对象时,仅需要维持一个指向其后继者的引用。
  • 指责链灵活性增加,即增加或删除一个职责链时,只需要重新建立链接即可。

缺点

  • 职责链过长时,引起性能问题。
  • 请求没有明确的接受者,导致请求可能没被处理。