一起学习设计模式:责任链模式

一起学习设计模式:责任链模式

采购单的分级审批

一起学习设计模式:责任链模式

每个公司可能都有自己的采购审批模式,那么如何在软件中设计这样一个采购订单的分级审批?

[En]

Each company may have its own purchase approval model, so how to design such a hierarchical approval of purchase orders in the software?

假如 Sunny 软件公司开发人员提出了一个初始解决方法,在系统中 提供一个采购单处理类 ​ ​PurchaseRequestHandler​​ 用于才统一处理采购单,代码如下:

// 采购单处理类class PurchaseRequestHandler {  // 递交采购单给主任  public void sendRequestToDirector(PurchaseRequest request) {    if (request.getAmount() < 50000) {      // 主任可以审批该采购单      this.handleByDirector(request);    }    else if (request.getAmount() < 100000) {      // 副董事长可审批      this.handleByVicePresident(request);    }    else if (request.getAmount() < 500000) {      // 董事长可审批      this.handleByPresident(request);    }    else {      // 董事会可审批      this.handleByCongress(request);    }  }      // 主任审批采购单  public void handleByDirector(PurchaseRequest request) {    // 代码省略  }    public void handleByVicePresident(PurchaseRequest request) {    // to do  }    public void handleByPresident(PurchaseRequest request) {    // to do  }    public void handleByCongress(PurchaseRequest request) {    // to do  }

通过上面的代码可以很容易地实现流程审批,但仔细看,有三个问题:

[En]

Process approval can be easily achieved through the above code, but if you look carefully, there are three problems:

  1. &#x200B;PurchaseRequestHandle&#x200B;​ 类较为庞大,各个级别的审批方法都集中在一个类中,违反了单一职责原则,测试和维护难度大。
  2. 如果需要新增一个新的审批级别,或者调整任何一级的审批金额和审批细节时,都需要修改源代码并进行严格的测试;如果需要移除某一级别(例如金额为 10 万元及以上的采购单直接由董事长审批,不再设副董事长一职)时也必须对源代码进行修改,违反了开闭原则。
  3. 审批流程的设置缺乏灵活性,现在的审批流程是”主任->副董事长->董事长->董事会”,如果需要改为”主任->董事长->董事会”,在此方案中只能通过修改源代码来实现,客户端无法定制审批流程。

针对这 3 个缺点,可以通过责任链模式解决。

责任链模式

责任链模式,又被称为 职责链模式、命令链、CoR、Chain of Command、Chain of Responsibility。

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

责任链模式为请求创建一个处理对象链。避免耦合请求的发送者和接收者,让多个对象有机会接收请求,将其连接到链中,并沿链传递请求,直到对象处理它。

[En]

The chain of responsibility pattern creates a chain of processing objects for requests. Avoid coupling the sender and receiver of the request, giving multiple objects the opportunity to receive the request, connect it into a chain, and pass the request along the chain until an object processes it.

发起请求和处理请求的过程是解耦的:责任链上的处理器负责处理请求,客户只需将请求发送到责任链,而不需要关注请求的处理细节和交付。

[En]

The process of initiating the request and processing the request is decoupled: the processor on the responsibility chain is responsible for handling the request, and the customer only needs to send the request to the responsibility chain without paying attention to the processing details and delivery of the request.

责任链模式结构

一起学习设计模式:责任链模式
  1. 抽象处理者 (Han­dler) 声明了所有具体处理者的通用 接口。一般设计为抽象类, 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法。
  2. 基础处理者 (Base Han­dler) 是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。

通常情况下, 该类中定义了一个保存对于下个处理者引用的成员变量。 客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。

  1. 具体处理者 (Con­crete Han­dlers) 包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。

处理器通常是独立和不可变的,需要通过构造函数一次获得所有必要的数据。

[En]

The processor is usually independent and immutable and needs to obtain all the necessary data at once through the constructor.

  1. 客户端 (Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。

抽象处理程序的典型代码如下所示:

[En]

The typical code for an abstract handler is as follows:

abstract class Handler {  protected Handler successor;    public void setSuccessor(Handler successor) {    this.successor = successor;  }    public abstract void handleRequest(String request);}

上述代码中,抽象处理者类定义了对下家的引用对象,以便将请求转发给下家,该对象的访问符可设为 protected,在其子类中可以使用。在抽象处理类中声明抽象的请求处理方法,具体实现交给子类完成。

具体处理者的两个作用:

  1. 处理请求,不同的具体处理者以不同的形式实现抽象请求处理方法 handleRequest()
  2. 转发请求,如果该请求超出了当前处理者类的处理范围,可以将该请求转发给下家

代码如下:

class ConcreteHandler extends Handler {  public void handleRequest(String request) {    if (请求满足条件) {      // 处理请求    }    else {      this.successor.handleRequest(request); // 转发请求    }  }}

责任链模式适用场景

  • 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
  • 当必须按顺序执行多个处理者时, 可以使用该模式。无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。
  • 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。

参考链接:

Original: https://blog.51cto.com/yuzhou1su/5639179
Author: 宇宙之一粟
Title: 一起学习设计模式:责任链模式

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/500204/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球