23种设计模式之责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、在找到正确的处理对象之前,所有的条件判定都要执行一遍,当责任链过长时,可能会引起性能的问题。 3、可能不容易观察运行时的特征,有碍于除错。
应用实例: 1、JS 中的事件冒泡。2、在现实生活中,有很多请求并不是一个人说了就算的,例如面试时的工资,低于1万的薪水可能技术经理就可以决定了,但是1万~1万5的薪水可能技术经理就没这个权利批准,可能就需要请求技术总监的批准,所以在面试的完后,经常会有面试官说,你这个薪水我这边觉得你这技术可以拿这个薪水的,但是还需要技术总监的批准等的话。
主要涉及两个角色:
- 抽象处理者角色(Handler):定义出一个处理请求的接口。这个接口通常由接口或抽象类来实现。
- 具体处理者角色(ConcreteHandler):具体处理者接受到请求后,可以选择将该请求处理掉,或者将请求传给下一个处理者。因此,每个具体处理者需要保存下一个处理者的引用,以便把请求传递下去
实现代码:
public abstract class AbstractAuditor
{
public string Name { get; set; }
public abstract void Audit(ApplyContext context); private AbstractAuditor _NextAuditor = null;
public void SetNext(AbstractAuditor auditor)
{
this._NextAuditor = auditor;
}
protected void AuditNext(ApplyContext context)
{
if (this._NextAuditor != null)
{
this._NextAuditor.Audit(context);
}
else
{
context.AuditResult = false;
context.AuditRemark = "不允许请假!";
}
}
}
/// <summary>
/// 请假申请,
/// Context--上下文环境,保存业务处理中参数-中间结果-最终结果
/// 行为型设计模式常用的标配
/// 把行为转移,
/// </summary>
public class ApplyContext
{
public int Id { get; set; }
public string Name { get; set; }
/// <summary>
/// 请假时长
/// </summary>
public int Hour { get; set; }
public string Description { get; set; }
public bool AuditResult { get; set; }
public string AuditRemark { get; set; }
}
/// <summary>
/// 职责问题:
/// 1 权限范围内,审批通过
/// 2 权限范围外,交给下一环节审批
/// 写的代码又多了一个,指定下一环节
/// 甩锅大法
/// </summary>
public class PM : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
}
}
}
public class Charge: AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
}
}
}
public class Manager : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
}
}
}
public class Chief : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
//....
}
}
}
public class CEO : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
//....
}
}
}
public class ChiarMan : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
//....
}
}
}
前端调用:
ApplyContext context = new ApplyContext()
{
Id = ,
Name = "aaa",
Hour = ,
Description = "我想...",
AuditResult = false,
AuditRemark = ""
};
//流程的可扩展 AbstractAuditor auditor = AuditorBuilder.Build();
auditor.Audit(context);
if (!context.AuditResult)
{
Console.WriteLine("不干了!");
}
//把流程环节逻辑从业务类转移了
public class AuditorBuilder
{
/// <summary>
/// 那就反射+配置文件
/// 链子的组成都可以通过配置文件
/// </summary>
/// <returns></returns>
public static AbstractAuditor Build()
{
AbstractAuditor pm = new PM()
{
Name = "bbb"
};
AbstractAuditor charge = new Charge()
{
Name = "ccc"
};
AbstractAuditor manager = new Manager()
{
Name = "ddd"
};
AbstractAuditor chief = new Chief()
{
Name = "eee"
};
AbstractAuditor ceo = new CEO()
{
Name = "fff"
}; pm.SetNext(charge);
charge.SetNext(manager);
//pm.SetNext(manager);
manager.SetNext(chief);
chief.SetNext(ceo);
ceo.SetNext(new ChiarMan()
{
Name = "ggg"
});
return pm;
}
}
代码中存在多个if-else语句的情况下,此时可以考虑使用责任链模式来对代码进行重构
本文参考文档:
https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html
https://www.cnblogs.com/zhili/p/ChainOfResponsibity.html
https://www.cnblogs.com/abcdwxc/archive/2007/09/25/905622.html
23种设计模式之责任链模式(Chain of Responsibility Pattern)的更多相关文章
- 二十四种设计模式:责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern) 介绍为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求.将这些对象连成一条链,并沿着这条链传递该请求,直 ...
- 乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern)
原文:乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 责任链模式(Chain of R ...
- 23种设计模式之责任链模式(Chain of Responsibility)
责任链模式是一种对象的行为型模式,避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止.责任链模式不保证每个请求都被接受, ...
- 【Unity与23种设计模式】责任链模式(Chain of Responsibility)
GoF中定义: "让一群对象都有机会来处理一项请求,以减少请求发送者与接收者之间的耦合度.将所有的接受对象串联起来,让请求沿着串接传递,直到有一个对象可以处理为止." 举个现实中的 ...
- 23种设计模式--责任链模式-Chain of Responsibility Pattern
一.责任链模式的介绍 责任链模式用简单点的话来说,将责任一步一步传下去,这就是责任,想到这个我们可以相当击鼓传花,这个是为了方便记忆,另外就是我们在项目中经常用到的审批流程等这一类的场景时我们就可以考 ...
- C#设计模式-责任链模式(Chain of Responsibility Pattern)
引子 一个事件需要经过多个对象处理是一个挺常见的场景,譬如采购审批流程,请假流程,软件开发中的异常处理流程,web请求处理流程等各种各样的流程,可以考虑使用责任链模式来实现.现在以请假流程为例,一般公 ...
- [设计模式] 13 责任链模式 Chain of Responsibility
转 http://blog.csdn.net/wuzhekai1985 http://www.jellythink.com/archives/878 向项目经理提交了休假申请,我的项目经理向 ...
- 设计模式 笔记 责任链模式 chain of responsibility
//---------------------------15/04/25---------------------------- //Chain of responsibility 责任链----- ...
- 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)
责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...
随机推荐
- MySQL数据库之表的增删改查
目录 MySQL数据库之表的增删改查 1 引言 2 创建表 3 删除表 4 修改表 5 查看表 6 复制表 MySQL数据库之表的增删改查 1 引言 1.MySQL数据库中,数据库database就是 ...
- Delphi - Windows自动计划任务与ParamStr详解
Windows自动计划任务与ParamStr详解 ParamStr函数: ParamStr(1),..ParamStr(N) ParamStr(1)代表程序入口的第一个参数,同理,ParamStr(N ...
- stage_ros的world文件配置方法
官方文档参阅:http://rtv.github.io/Stage/modules.html stage_ros是一个基于stage的2D模拟器,用于ROS的仿真测试.虽然现在越来越多的人在使用gaz ...
- (一)LinkedList集合解析及手写集合
一.LinkedList集合特点 问题 结 论 LinkedList是否允许空 允许 LinkedList是否允许重复数据 允许 LinkedList是否有序 有序 LinkedList是否 ...
- LuoGu-P1239计数器-强大的贡献
P1239 计数器 题意:就是求从1到n间,1-9一共出现的次数 这道题直接暴力是不科学的,因为N有 1e9: 然后我就看到了一个很好的从贡献思考的方法: ——>转自洛谷学神的方法: 楼下dal ...
- CF989C A Mist of Florescence 构造 思维好题 第八题
A Mist of Florescence time limit per test 1 second memory limit per test 256 megabytes input standar ...
- eql框架。
在刚进入公司的时候,在service层的框架用的是eql,是公司内的大佬封装的,作为一个小白,真的是折磨.公司内没有任何的文档,只能靠着自己一步一步的摸索. 后来用习惯了,发现这个框架确实有自己的独到 ...
- 字符串的api
一.基础 1.字符串.charAt(index) 根据下标获取字符串的某一个字符 应用: 判断字符串的首字母是否大写 任意给定的一串字母,统计字符串里面的大写字母和小写字母的个数 2.字符串.inde ...
- 结合生活案例实现rabbitmq消息通信
title: 基于springboot实现rabbitmq消息通信 date: 2019-09-11 09:00:30 tags: - [rabbitmq] categories: - [spring ...
- git 中文乱码-一次被坑经历
git log和gitcommit中文出现乱码,花了大半天的时间试了网上的各种方法,还是搞不定. 只好放大招. 卸载软件后重装,还是不行.然后git config --list 发现一些奇怪的配置信息 ...