十六、行为型(责任链模式)

ops/2024/10/25 2:23:44/

责任链模式(Chain of Responsibility Pattern)

概念
责任链模式是一种行为型设计模式,它使多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

责任链模式的核心思想是把请求的处理责任从一个对象转移到多个对象上。通过设置链式处理机制,多个对象可以动态参与请求处理,同时提高系统的可扩展性。


应用场景

  1. 多处理器处理请求:当一个请求可能被多个对象处理时,可以采用责任链模式将这些处理对象串联起来,沿着链条传递请求,直到找到合适的处理者。

  2. 避免复杂条件判断:如果在处理某些请求时,需要使用大量的条件语句(if-elseswitch-case),可以通过责任链模式将处理逻辑分散到不同的对象中,从而避免代码臃肿、难以维护。

  3. 日志过滤或权限控制:在日志记录或权限验证的场景中,不同的日志级别或权限控制可以使用责任链模式进行逐级处理。例如,日志系统可以根据不同的日志级别决定是否记录或输出日志信息。

  4. 审批流程:当一个请求需要经过多级审批时,责任链模式可以很好地实现逐级审批的机制。如果某一级不能处理,则传递给下一层。


注意点

  1. 请求必须能最终得到处理责任链模式的链条中必须有一个对象能够处理请求,否则请求可能被丢失。

  2. 链条过长时可能影响性能:如果链条中包含的处理者对象很多,请求在链中传递的时间可能会较长,因此链的长度不宜过长。

  3. 容易出现不必要的调用:如果链条中的某些处理者不必要地调用了处理方法,可能会导致不必要的性能开销。


核心要素

  1. Handler(处理者接口/抽象类):定义处理请求的接口,同时包含设置下一个处理者的方法。

  2. ConcreteHandler(具体处理者):实现处理者接口的类,负责处理具体的请求,或者将请求传递给下一个处理者。

  3. Client(客户端):向链条上的处理者提交请求,由处理者决定如何处理该请求。


Java代码完整示例

示例:银行审批系统的责任链模式实现

// 抽象处理者
abstract class Approver {protected Approver nextApprover;  // 下一个处理者public void setNextApprover(Approver nextApprover) {this.nextApprover = nextApprover;}// 处理请求的抽象方法public abstract void approveRequest(int amount);
}// 具体处理者:经理
class Manager extends Approver {@Overridepublic void approveRequest(int amount) {if (amount <= 1000) {System.out.println("Manager approved request of amount " + amount);} else if (nextApprover != null) {nextApprover.approveRequest(amount);  // 传递给下一个处理者}}
}// 具体处理者:总监
class Director extends Approver {@Overridepublic void approveRequest(int amount) {if (amount <= 5000) {System.out.println("Director approved request of amount " + amount);} else if (nextApprover != null) {nextApprover.approveRequest(amount);  // 传递给下一个处理者}}
}// 具体处理者:CEO
class CEO extends Approver {@Overridepublic void approveRequest(int amount) {if (amount > 5000) {System.out.println("CEO approved request of amount " + amount);} else if (nextApprover != null) {nextApprover.approveRequest(amount);}}
}// 客户端代码
public class ChainOfResponsibilityDemo {public static void main(String[] args) {Approver manager = new Manager();Approver director = new Director();Approver ceo = new CEO();// 设置责任链:经理 -> 总监 -> CEOmanager.setNextApprover(director);director.setNextApprover(ceo);// 提交请求System.out.println("Requesting approval for amount 500:");manager.approveRequest(500);  // Manager handles this requestSystem.out.println("\nRequesting approval for amount 3000:");manager.approveRequest(3000);  // Director handles this requestSystem.out.println("\nRequesting approval for amount 10000:");manager.approveRequest(10000);  // CEO handles this request}
}

输出结果

Requesting approval for amount 500:
Manager approved request of amount 500Requesting approval for amount 3000:
Director approved request of amount 3000Requesting approval for amount 10000:
CEO approved request of amount 10000

各种变形用法完整示例

  1. 动态责任链

    在某些情况下,责任链的顺序可能并不是固定的。可以动态设置处理者链条,从而灵活地控制请求的传递顺序。

    代码示例:动态责任链

    public class DynamicChainDemo {public static void main(String[] args) {Approver manager = new Manager();Approver director = new Director();Approver ceo = new CEO();// 动态设置责任链director.setNextApprover(manager);  // 将总监设置为经理的下一个处理者ceo.setNextApprover(director);      // 将CEO设置为总监的下一个处理者// 提交请求System.out.println("Requesting approval for amount 2000:");ceo.approveRequest(2000);  // 由于链条是动态的,总监会首先处理}
    }
    

    输出结果

    Requesting approval for amount 2000:
    Director approved request of amount 2000
    
  2. 双向责任链

    有时请求可能需要在链条中向前或向后传递。在这种情况下,可以实现双向责任链。

    代码示例:双向责任链

    abstract class BiDirectionalApprover {protected BiDirectionalApprover nextApprover;protected BiDirectionalApprover prevApprover;public void setNextApprover(BiDirectionalApprover nextApprover) {this.nextApprover = nextApprover;}public void setPrevApprover(BiDirectionalApprover prevApprover) {this.prevApprover = prevApprover;}public abstract void approveRequest(int amount);
    }class ManagerBiDirectional extends BiDirectionalApprover {@Overridepublic void approveRequest(int amount) {if (amount <= 1000) {System.out.println("Manager approved request of amount " + amount);} else if (nextApprover != null) {nextApprover.approveRequest(amount);} else if (prevApprover != null) {prevApprover.approveRequest(amount);  // 向前传递}}
    }// 双向链条示例
    public class BiDirectionalChainDemo {public static void main(String[] args) {BiDirectionalApprover manager = new ManagerBiDirectional();BiDirectionalApprover director = new DirectorBiDirectional();BiDirectionalApprover ceo = new CEO();// 设置链条manager.setNextApprover(director);director.setPrevApprover(manager);// 请求manager.approveRequest(2000);}
    }
    
  3. 链式日志处理

    在日志系统中,可以使用责任链模式实现日志的逐级过滤。例如,只输出大于某个级别的日志。

    代码示例:链式日志处理

    // 抽象日志处理者
    abstract class Logger {public static int INFO = 1;public static int DEBUG = 2;public static int ERROR = 3;protected int level;protected Logger nextLogger;public void setNextLogger(Logger nextLogger) {this.nextLogger = nextLogger;}public void logMessage(int level, String message) {if (this.level <= level) {write(message);}if (nextLogger != null) {nextLogger.logMessage(level, message);}}protected abstract void write(String message);
    }// 具体日志处理者
    class ConsoleLogger extends Logger {public ConsoleLogger(int level) {this.level = level;}@Overrideprotected void write(String message) {System.out.println("Console Logger: " + message);}
    }class FileLogger extends Logger {public FileLogger(int level) {this.level = level;}@Overrideprotected void write(String message) {System.out.println("File Logger: " + message);}
    }// 日志系统示例
    public class LoggerDemo {public static void main(String[] args) {Logger consoleLogger = new ConsoleLogger(Logger.INFO);Logger fileLogger = new FileLogger(Logger.ERROR);// 设置链条consoleLogger.setNextLogger(fileLogger);consoleLogger.logMessage(Logger.INFO, "This is an information.");consoleLogger.logMessage(Logger.ERROR, "This is an error message.");}
    }
    

通过这些示例,可以灵活运用责任链模式,根据业务需求构建多种责任链。


http://www.ppmy.cn/ops/128211.html

相关文章

docker 误删gitlab文件,另类的删库跑路,如何进行恢复?

缘起&#xff1a;由于看到linux服务器内存快满了&#xff0c;于是本着责任感&#xff0c;想着清理一下内存&#xff0c;结果在看到docker文件占了20多个G&#xff0c;于是想着&#xff0c;我们就三个容器&#xff0c;为啥这么大&#xff0c;肯定是有诈&#xff0c;于是就一个个…

freeswitch-esl动态控制录制音频(开始、停止)

场景描述:在控制freeswitch中使用ESL socket连接,其实类型连接TCP差不多。 当A和B在通话中,我想录制它们通话内容,录制格式为wav格式音频文件。代码如下#include <iostream> #include <string> #include <esl/esl.h><

使用docker-compose搭建redis7集群-3主3从

下面是一个用于搭建 Redis 集群的 docker-compose.yml 示例文件&#xff0c;它会启动 6 个 Redis 节点&#xff08;3 主节点 3 从节点&#xff09;来构成一个最小的 Redis 集群。 同一个容器内网通讯没问题&#xff0c;但是你要是需要暴露到外网你需要用第二个yml 内网的 v…

『完整代码』坐骑召唤

创建一个按钮 作为召唤/消失坐骑的开关 将预制体放入指定文件夹 命名为Mount01 创建脚本并编写&#xff1a;CallMount.cs using UnityEngine; using UnityEngine.UI; public class CallMount : MonoBehaviour{public Button callBtn;GameObject mountPrefab;GameObject mountIn…

uniapp移动端优惠券! 附源码!!!!

本文为常见的移动端uniapp优惠券&#xff0c;共有6种优惠券样式&#xff08;参考了常见的优惠券&#xff09;&#xff0c;文本内容仅为示例&#xff0c;您可在此基础上调整为你想要的文本 预览效果 通过模拟数据&#xff0c;实现点击使用优惠券让其变为灰色的效果&#xff08;模…

LeetCode 第420场周赛个人题解

目录 Q1. 出现在屏幕上的字符串序列 原题链接 思路分析 AC代码 Q2. 字符至少出现 K 次的子字符串 I 原题链接 思路分析 AC代码 Q3. 使数组非递减的最少除法操作次数 原题链接 思路分析 AC代码 Q4. 判断 DFS 字符串是否是回文串 原题链接 思路分析 AC代码 Q1. 出…

ReactNative项目根据平台去判断允许用户是热更新还是强更新或者若更新

在 React Native 项目中&#xff0c;根据平台&#xff08;iOS 或 Android&#xff09;来决定是否允许用户进行热更新、强更新或弱更新&#xff0c;通常需要考虑以下几个因素&#xff1a; 平台政策&#xff1a; iOS&#xff1a;App Store 严格限制了热更新的能力&#xff0c;因此…

大数据新视界 --大数据大厂之数据脱敏技术在大数据中的应用与挑战

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…