职责链模式(Chain of Responsibility Pattern)

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/130 访问。

职责链模式属于行为型模式,它为请求创建了一个接收者对象的链。这种模式给予一个具体请求的类型,对请求的发送者和接收者进行解耦。

通常有2种方法来实现该模式。第1种是每个接收者都包含对下一个接收者的引用,以便在不能处理该请求时,转派请求至下一个接收者。第2个方法是引入中间链条类,由中间件负责转派请求。第一种方法的实现较为简单,本例采用第2种实现方式。

角色:

1、抽象处理者(Handler)

定义出一个处理请求的接口。接口可以定义出一个方法以设定和返回对链条中下一个处理者的引用,如果使用第2种方式实现,可无需引用下一个处理者,统一由中间件负责;

2、具体处理者(Concrete Handler)

具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家;

3、请求类(Request)

处理者需要处理的请求信息;

4、中间链条类(Chain)

若使用第2种方式实现,则需要引入此中间类,内部维护所有处理者,并在需要时自动转派请求至下一个处理者。

示例:

命名空间ChainOfResponsibility包含领导Leader类充当处理者基类,它包含4个实现类,经理类Manager、总监类Inspector、总经理类President和董事Directorate类,请假信息LeaveRequest类充当请求类,LeaderChain类充当中间链条类。本案例尝试以员工请假来解释职责链模式在审批环节的应用。

namespace ChainOfResponsibility
public class LeaveRequest {

    public int Days { get; set; }

    public string Name { get; set; }

    public LeaveRequest(int days, string name) {
Days = days;
Name = name;
} }

请假请求LeaveRequest类,包含需要请假的天数和员工的姓名。一个公开的构造函数表明调用方必须提供请假天数和员工姓名信息。

public abstract class Leader {

    protected string Name { get; set; }

    protected Leader(string name) {
this.Name = name;
} public static LeaderChain Chain { protected get; set; } public abstract void ProcessRequest(LeaveRequest request); protected void Delivery(LeaveRequest request) {
Chain.DoChain(request);
} }

领导者Leader类,充当处理者基类,包含领导的姓名Name并维持对中间链的引用。ProcessRequest为处理请假的抽象方法,为处理请假公开了一个调用接口。Delivery则为在不能处理请求时转派至下一个处理者。

public class Manager : Leader {

    public Manager(string name) : base(name) { }

    public override void ProcessRequest(LeaveRequest request) {
if (request.Days <= 2) {
Console.WriteLine($"{this.Name} approved {request.Name}'s " +
$"leave request for {request.Days} days!");
return;
}
Delivery(request);
} }

具体处理者,经理Manager类,如果员工的请假天数小于等于2天,则经理有权限批准该请假请求。

public class Inspector : Leader {

    public Inspector(string name) : base(name) { }

    public override void ProcessRequest(LeaveRequest request) {
if (request.Days <= 4) {
Console.WriteLine($"{this.Name} approved {request.Name}'s " +
$"leave request for {request.Days} days!");
return;
}
Delivery(request);
} }

具体处理者,总监Inspector类,如果员工的请假天数小于等于4天,则总监有权限批准该请假请求。

public class President : Leader {

    public President(string name) : base(name) { }

    public override void ProcessRequest(LeaveRequest request) {
if (request.Days <= 8) {
Console.WriteLine($"{this.Name} approved {request.Name}'s " +
$"leave request for {request.Days} days!");
return;
}
Delivery(request);
} }

具体处理者,总经理President类,如果员工的请假天数小于等于8天,则总经理有权限批准该请假请求。

public class Directorate : Leader {

    public Directorate(string name) : base(name) { }

    public override void ProcessRequest(LeaveRequest request) {
if (request.Days > 8) {
Console.WriteLine($"{this.Name} approved {request.Name}'s " +
$"leave request for {request.Days} days!");
return;
}
Delivery(request);
} }

具体处理者,董事Directorate类,如果员工的请假天数大于8天,则需要董事会批准该请假请求。

public class LeaderChain {

    private List<Leader> _leaders = new List<Leader>();

    private int _cursor = 0;

    public void Attach(Leader leader) {
if (leader == null) throw new ArgumentNullException();
_leaders.Add(leader);
} public bool Detach(Leader leader) {
if (leader == null) throw new ArgumentNullException();
return _leaders.Remove(leader);
} public void DoChain(LeaveRequest request) {
if (_cursor <= _leaders.Count - 2) {
_leaders[++_cursor].ProcessRequest(request);
}
_cursor = 0;
} }

中间链条类LeaderChain,首先内部维持对所有处理者的引用,包含的游标_cursor指示链条所处的位置,Attach和Detach方法分别向链条中增加和删除处理者。而DoChain方法则真正转派请求至下一个处理者。

此处需要注意的是,由于请求信息是由第一个处理者直接调用的,所以初始游标位置为0并且在DoChain方法中使用++_cursor作为处理者列表的索引参数。也就是说当第一次转派请求时,索引的值为1(因为使用了++_cursor),即为链条中的第2个处理者。请各位看官仔细思考此处逻辑。

public class Program {

    public static void Main(string[] args) {
var leaders = new List<Leader>{
new Manager("Tom"),
new Inspector("Juice"),
new President("Iori"),
new Directorate("Marin")
}; var chain = new LeaderChain();
foreach (var leader in leaders) {
chain.Attach(leader);
} Leader.Chain = chain; var requests = new List<LeaveRequest> {
new LeaveRequest(1, "Zhao"),
new LeaveRequest(3, "Qian"),
new LeaveRequest(5, "Sun"),
new LeaveRequest(7, "Li"),
new LeaveRequest(12, "Zhou")
}; foreach (var request in requests) {
leaders[0].ProcessRequest(request);
} Console.ReadKey();
} }

以上为调用方代码的示例,首初始化一个处理者列表并增加至中间链条类,之后模拟“赵、钱、孙、李、周”5位同学的请假请求,他们分别要请1、3、5、7、12天假,最后调用ProcessRequest处理请求。以下是这个案例的输出结果:

Tom approved Zhao's leave request for 1 days!
Juice approved Qian's leave request for 3 days!
Iori approved Sun's leave request for 5 days!
Iori approved Li's leave request for 7 days!
Marin approved Zhou's leave request for 12 days!

优点:

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/130 访问。

1、降低耦合度,它将请求的发送者和接收者解耦;

2、简化了对象,使得对象不需要知道链的结构;

3、增强给对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任;

4、增加新的请求处理者类很方便。

缺点:

1、不能保证请求一定被接收;

2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用;

3、可能不容易观察运行时的特征,不利于程序的调试。

使用场景:

1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时确定;

2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;

3、需要动态指定一组对象处理请求。

C#设计模式之13-职责链模式的更多相关文章

  1. 设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型)

     设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就 ...

  2. Java设计模式之《职责链模式》及应用场景

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6530089.html 职责链模式(称责任链模式)将请求的处理对象像一条长链一般组合起来,形 ...

  3. 设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为)

     设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决.不能解决就 ...

  4. 大话设计模式Python实现-职责链模式

    职责链模式(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免发送者和接收者的耦合关系.将对象连成链并沿着这条链传递请求直到被处理 下面是一个设计模式的demo: ...

  5. C#设计模式系列:职责链模式(Chain of Responsibility)

    1.职责链模式简介 1.1>.定义 职责链模式是一种行为模式,为解除请求的发送者和接收者之间的耦合,而使多个对象都有机会处理这个请求.将这些对象连接成一条链,并沿着这条链传递该请求,直到有一个对 ...

  6. OOP设计模式[JAVA]——03职责链模式

    职责链模式 Responsibility of Chain 在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求 ...

  7. 设计模式入门之职责链模式Chain Of Responsibility

    //职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. //实例:申请费用的功能,不同金额的费 ...

  8. java设计模式-----18、职责链模式

    概念: Chain of Responsibility(CoR)模式也叫职责链模式.责任链模式或者职责连锁模式,是行为模式之一,该模式构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的 ...

  9. 设计模式之笔记--职责链模式(Chain of Responsibility)

    职责链模式(Chain of Responsibility) 定义 职责链模式(Chain of Responsibility),使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系 ...

  10. JAVA设计模式之【职责链模式】

    职责链模式 专门处理请求链式传递的模式 角色 Handler抽象处理者 ConcreteHandler具体处理者 在职责链模式中,很多对象由每一个对象对其下家的引用而连接成一条链,请求在这条链上传递, ...

随机推荐

  1. 初级软件工程师怎么走向BATJ?——献给迷茫中的测试人

    软件测试,邀你同行.你好,我是爱码小哥. 又是一个深夜,打开手机备忘录,想记录一些东西,本人比较静的一个人,所以经常会去 IT行业的贴吧论坛交流一下,逛知乎,论坛,社区你就会发现大量这样的帖子,都会出 ...

  2. Python 3基础教程8-if else语句

    终于更新到了,教程8, 如果对python软件测试.接口测试.自动化测试.面试经验交流.感兴趣可以加君羊软件测试交流: 1079636098,还会有同行一起技术交流. 本文介绍if else语句,不多 ...

  3. 集训作业 洛谷P1017 进制转换

    这个题的题目真的太恶心了. 重点是他的题目描述和他的目标没啥关系. 和最终目的有关系的只有这么一句话:”输出此负进制数及其基数,若此基数超过10,则参照16进制的方法处理.“ 我们通过看这句话可以发现 ...

  4. 2019CSP-J T4 加工零件

    题目描述 凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇.工厂里有 n 位工人,工人们从 1 ∼n 编号.某些工人之间存在双向的零件传送带.保证每两名工人之间最多只存在一 ...

  5. ATX学习(一)-atx-server

    今天无意中发现了ATX手机设备管理平台,瞬间勾引起了我极大的兴趣,这里对学习过程中的情况做个记录. 1.搭建环境 先按照作者步骤搭建环境出来吧,哇,突然发现ATX搭建环境很方便(一会就搭建好了)   ...

  6. 部署一套完整的Kubernetes高可用集群(二进制,v1.18版)

    一.前置知识点 1.1 生产环境可部署Kubernetes集群的两种方式 目前生产部署Kubernetes集群主要有两种方式: kubeadm Kubeadm是一个K8s部署工具,提供kubeadm ...

  7. 死磕Spring源码之AliasRegistry

    死磕Spring源码之AliasRegistry 父子关系 graph TD; AliasRegistry-->BeanDefinitionRegistry; 代码实现 作为bean定义的最顶层 ...

  8. Go操作腾讯云COS对象存储的简单使用案例

    准备环境 安装Go环境 Golang:用于下载和安装 Go 编译运行环境,请前往 Golang 官网进行下载 安装SDK go get -u github.com/tencentyun/cos-go- ...

  9. [难题题解] [BZOJ1875] [SDOI2009] HH去散步

    题目H有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因为HH是个喜欢变化的人 ...

  10. Python 字典(Dictionary) copy()方法

    描述 Python 字典(Dictionary) copy() 函数返回一个字典的浅复制.高佣联盟 www.cgewang.com 语法 copy()方法语法: dict.copy() 参数 NA. ...