C#设计模式学习笔记:(20)职责链模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8109100.html,记录一下学习过程以备后续查用。
一、引言
今天我们要讲行为型设计模式的第八个模式--职责链模式。让我们看看现实生活中某公司采购流程的例子吧,理解起来可能更容易。某公司的规章制度
规定,采购原材料的总价在5万之内,只需要经理级别的人批准即可;采购总价大于5万小于10万的则需要财务经理进行批准;总价大于10万小于30万的
需要总经理批准;总价大于30万的则需要通过董事会会议讨论决定。对于这样一个需求,最直接的方法就是设计一个方法,该方法接受的参数是采购的总
价,然后在这个方法内对价格进行判断,然后针对不同的条件交给不同级别的角色去处理。如果情况就是这样,不变了,这样做很好,没问题。如果我们
又有新的条件要增加该怎么办呢?我们不得不去修改原来设计的方法来再添加一个条件判断,让本已多重的if-else判断语句更多了,这样的设计显然违背
了“开闭原则”。这时候,我们可以采用职责链模式来解决这样的问题。
二、职责链模式介绍
职责链模式:英文名称--Chain of Responsibility Pattern;分类--行为型。
2.1、动机(Motivate)
在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者
的紧耦合。如何使请求的发送者不需要指定具体的接受者,让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。
2.2、意图(Intent)
避免请求发送者与接收者耦合在一起,让多个对象都有可能接受请求,将这些对象连接成一条链,并且沿着这条链传递请求,知道有对象处理它为止。
——《设计模式》GoF
2.3、结构图(Structure)
2.4、模式的组成
可以看出,在职责链模式的结构图有以下角色:
1)抽象处理者角色(Handler):抽象处理者定义了一个处理请求的接口,它一般设计为抽象类。由于不同的具体处理者处理请求的方式不同,因此在
其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个自类型的对象,作为其对下家的引用。通过该
引用,处理者可以连成一条链。
2)具体处理者角色(ConcreteHandler):具体处理者是抽象处理者的子类,它可以处理用户请求。在具体处理者类中实现了抽象处理者中定义的抽象
处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限?如果可以处理请求就处理它,否则将请求转发给后继者。在具体处理者中可以访问
链中下一个对象,以便请求的转发。
2.5、职责链模式的具体实现
在现实生活中,职责链模式的例子也是很多的,例如:公司的请假流程就是一个很好的职责链模式的例子。如果请假半天,只要告诉本部门经理就可以
了;如果请假7天或者以上必须人事总监批准;如果请假15天以上,那就要经过总裁批准了。还有类似的例子就是采购的流程,其流程也是职责链模式很
好的体现,采购金额的不同,需要批准的人员也不同。下面就以采购的实例来说明职责链模式,实现代码如下:
class Program
{
/// <summary>
/// 采购请求
/// </summary>
public sealed class PurchaseRequest
{
//金额
public double Amount { get; set; } //产品名字
public string ProductName { get; set; } public PurchaseRequest(double amount, string productName)
{
Amount = amount;
ProductName = productName;
}
} /// <summary>
/// 抽象审批人--相当于“抽象处理者角色”
/// </summary>
public abstract class Approver
{
//下一位审批人,由此形成一条链。
public Approver NextApprover { get; set; } //审批人的名称
public string Name { get; set; } public Approver(string name)
{
Name = name;
} //处理请求
public abstract void ProcessRequest(PurchaseRequest request);
} /// <summary>
/// 部门经理--相当于“具体处理者角色”
/// </summary>
public sealed class Manager : Approver
{
public Manager(string name) : base(name) { } public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount <= 10000.0)
{
Console.WriteLine("部门经理{0}批准了对原材料{1}的采购计划。", Name, request.ProductName);
}
else if (NextApprover != null)
{
Console.WriteLine("部门经理{0}批准了对原材料{1}的采购计划。", Name, request.ProductName);
NextApprover.ProcessRequest(request);
}
}
} /// <summary>
/// 财务经理--相当于“具体处理者角色”
/// </summary>
public sealed class FinancialManager : Approver
{
public FinancialManager(string name) : base(name) { } public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount > 10000.0 && request.Amount <= 50000.0)
{
Console.WriteLine("财务经理{0}批准了对原材料{1}的采购计划。", Name, request.ProductName);
}
else if (NextApprover != null)
{
Console.WriteLine("财务经理{0}批准了对原材料{1}的采购计划。", Name, request.ProductName);
NextApprover.ProcessRequest(request);
}
}
} /// <summary>
/// 总裁--相当于“具体处理者角色”
/// </summary>
public sealed class CEO : Approver
{
public CEO(string name) : base(name) { } public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount > 50000.0 && request.Amount < 300000.0)
{
Console.WriteLine("总裁{0}批准了对原材料{1}的采购计划。", Name, request.ProductName);
}
else
{
Console.WriteLine("这个采购计划的金额比较大,需要董事会会议讨论才能决定。");
}
}
} static void Main(string[] args)
{
#region 职责链模式
PurchaseRequest requestDao = new PurchaseRequest(9000.0, "单刀5把");
PurchaseRequest requestHuaJi = new PurchaseRequest(40000.0, "10把方天画戟");
PurchaseRequest requestJian = new PurchaseRequest(90000.0, "5把金丝龙鳞闪电劈"); Approver manager = new Manager("黄飞鸿");
Approver financial = new FinancialManager("黄麒英");
Approver ceo = new CEO("十三姨"); //设置职责链
manager.NextApprover = financial;
financial.NextApprover = ceo; //处理请求
manager.ProcessRequest(requestDao);
Console.WriteLine();
manager.ProcessRequest(requestHuaJi);
Console.WriteLine();
manager.ProcessRequest(requestJian); Console.ReadLine();
#endregion
}
}
运行结果如下:
三、职责链模式的实现要点
Chain of Responsibility模式的应用场合在于“一个请求可能有多个接受者,但是最后真正的接受者只有一个”,只有这时候请求发送者与接受者的耦合才
有可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦,从而更好地应对变化。
应用了Chain of Responsibility模式后,对象的职责分派将更具灵活性,我们可以在运行时动态添加/修改请求的处理职责。
当我们要新增一个Handler处理请求,就不需再改原来的代码了,遵从了开放封闭原则。这样我们的程序就更赋予变化,更有变化的抵抗力。Handler类
本身继承自BaseHandler类型,又包含了一个BaseHandler类型的对象,这点类似Decorator模式。
如果请求传递到职责链的末尾仍得不到处理,应该有一个合理的缺省机制,这也是每一个接受对象的责任,而不是发出请求的对象的责任。
3.1、职责链模式的主要优点
1)降低耦合度:职责链模式使得一个对象无需知道是其它哪一个对象处理其请求,对象仅需知道该请求会被处理即可。接受者和发送者都没有对方的明
确信息,且链中的对象不需要知道链的结构,有客户端负责链的创建。
2)可简化对象的相互连接:接受者对象仅需维持一个指向其后继者的引用,而不需维持它对所有的候选处理者的引用。
3)增强给对象指派职责的灵活性:在给对象分派职责时,职责链可以给我们带来更多的灵活性。可以通过在运行时对该连进行动态的增加或修改处理一
个请求的职责。
4)增加新的请求处理类很方便:在系统中增加一个新的请求处理者无需修改原有系统的代码,只需要在客户端重新建链即可,从这一点看来是符合开闭
原则的。
3.2、职责链模式的主要缺点
1)在找到正确的处理对象之前,所有的条件判定都要执行一遍,当责任链过长时,可能会引起性能的问题。
2)可能导致某个请求不被处理。
3)客户端需要组装这个链条,耦合了客户端和链条的组成结构,可以把这个在客户端的组合动作提到外面,通过配置来做会更好点。
3.3、在下面的情况下可以考虑使用职责链模式
1)一个系统的审批需要多个对象才能完成处理的情况下,例如请假系统等。
2)代码中存在多个if-else语句的情况下,此时可以考虑使用责任链模式来对代码进行重构。
3)有多个对象可以处理同一个请求,具体哪个对象处理该请求在运行时刻自动确定。客户端只需将请求提交到链上,无须关心请求的处理对象是谁以及
它是如何处理的。
4)不明确指定接受者的情况下,向多个对象中的一个提交一个请求。请求的发送者与请求者解耦,请求将沿着链进行传递,寻求响应的处理者。
5)可动态指定一组对象处理请求。客户端可以动态创建职责链来处理请求,还可以动态改变链中处理者之间的先后次序。
四、.NET中职责链模式的实现
这个模式在.Net框架中的实现不多,个人觉得这个模式的使用场景更多的是在业务系统中才会有更大的用处。这种模式在处理UI的消息时很常用,但实际
上Windows消息循环还是硬编码的结构,主要是效率上的考虑。Windows消息循环是哪个对象有一个请求,则直接将请求送至处理函数的地址。如果链条上
的对象多了,而真正处理的函数在链条后部分,效率会很低下。因此我们在使用这种模式的时候更适合业务流程,即对性能要求不是特别高的情况更加常用。
五、总结
这个模式也是为了解耦,解耦请求的发送者和接受者,当有新的需求的时候更容易变化,让我们的代码更符合面向对象OO的设计。
C#设计模式学习笔记:(20)职责链模式的更多相关文章
- javascript设计模式学习之十三——职责链模式
一.职责链的定义和使用场景 职责链模式的定义是,职责链模式将一系列可能会处理请求的对象连接成一条链,请求在这些对象之间一次传递,直到遇到一个可以处理它的对象.从而避免请求的发送者和接收者之间的耦合关系 ...
- atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换
atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...
- Java设计模式学习笔记(三) 工厂方法模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...
- Java设计模式学习笔记(二) 简单工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
- 重温设计模式(三)——职责链模式(chain of responsibility)
一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...
- js设计模式(12)---职责链模式
0.前言 老实讲,看设计模式真得很痛苦,一则阅读过的代码太少:二则从来或者从没意识到使用过这些东西.所以我采用了看书(<js设计模式>)和阅读博客(大叔.alloyteam.聂微东)相结合 ...
- C#设计模式之二十一职责链模式(Chain of Responsibility Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中 ...
- C#设计模式之二十职责链模式(Chain of Responsibility Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中的例子吧,理解起来可能更 ...
随机推荐
- 轻松理解 Kubernetes 的核心概念
Kubernetes 迅速成为云环境中软件部署和管理的新标准. 与强大的功能相对应的是陡峭的学习曲线. 本文将提供 Kubernetes 的简化视图,从高处观察其中的重要组件,以及他们的关联. 硬件 ...
- 「 深入浅出 」集合Map
系列文章: 「 深入浅出 」java集合Collection和Map 「 深入浅出 」集合List 「 深入浅出 」集合Set 前面已经介绍完了Collection接口下的集合实现类,今天我们来介绍M ...
- Android的学习之路一
在Android的道路上越走越远==,本着一颗童心去学习,没想到最后会成为自己的职业.看到过知乎上写的,并不是兴趣使比尔盖茨以及乔布斯他们成就斐然,而是他们真正的牛逼使得即使买大饼也能成为世界首富.然 ...
- 双指针,BFS和图论(二)
(一)BFS 1.地牢大师 你现在被困在一个三维地牢中,需要找到最快脱离的出路! 地牢由若干个单位立方体组成,其中部分不含岩石障碍可以直接通过,部分包含岩石障碍无法通过. 向北,向南,向东,向西,向上 ...
- Python学习,第五课 - 列表、字典、元组操作
本篇主要详细讲解Python中常用的列表.字典.元组相关的操作 一.列表 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 通过下标获取元素 #先定义一个列表 le ...
- Python3 正则表达式 re 模块的使用 - 学习笔记
re 模块的引入 re 模块的使用 re.compile() re.match()与re.search() re.match re.search() 区别 re.findall()与re.findit ...
- Dynamics 365 CRM 在 Connected Field Service 中部署 IoT Central (一)- 配置 IoT Central和IoT alert
今天这个系列给大家带来怎样在connected field service中部署IoT Central 并且做连接. 首先, 这里提供微软官方的tutorial的链接https://docs.micr ...
- 基于OpenCV的双目视觉匹配测距系统
刚读研究生的时候,自己导师研究的方向是双目视觉,于是让自己研究OpenCV,折腾了几个月,算法上没啥突破,不过工程上还是折腾出了一个能用的小玩意,基于OpenCV实现了相机的标定.双目视觉图片的矫正. ...
- ThreeJS 物理材质shader源码分析(顶点着色器)
再此之前推荐一款GLTF物理材质在线编辑器https://tinygltf.xyz/ ThreeJS 物理材质shader源码分析(顶点着色器) Threejs将shader代码分为ShaderLib ...
- LeetCode刷题总结-链表
LeetCode刷题总结-链表 一.链表 链表分为单向链表.单向循环链表和双向链表,一下以单向链表为例实现单向链表的节点实现和单链表的基本操作. 单向链表 单向链表也叫单链表,是链表中最简单的 ...