本笔记摘抄自: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)职责链模式的更多相关文章

  1. javascript设计模式学习之十三——职责链模式

    一.职责链的定义和使用场景 职责链模式的定义是,职责链模式将一系列可能会处理请求的对象连接成一条链,请求在这些对象之间一次传递,直到遇到一个可以处理它的对象.从而避免请求的发送者和接收者之间的耦合关系 ...

  2. atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...

  3. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  4. Java设计模式学习笔记(二) 简单工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...

  5. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

  6. 重温设计模式(三)——职责链模式(chain of responsibility)

    一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...

  7. js设计模式(12)---职责链模式

    0.前言 老实讲,看设计模式真得很痛苦,一则阅读过的代码太少:二则从来或者从没意识到使用过这些东西.所以我采用了看书(<js设计模式>)和阅读博客(大叔.alloyteam.聂微东)相结合 ...

  8. C#设计模式之二十一职责链模式(Chain of Responsibility Pattern)【行为型】

    一.引言   今天我们开始讲"行为型"设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中 ...

  9. C#设计模式之二十职责链模式(Chain of Responsibility Pattern)【行为型】

    一.引言 今天我们开始讲“行为型”设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中的例子吧,理解起来可能更 ...

随机推荐

  1. moco响应中文乱码

    moco版本为:moco-runner-standalone-0.11.1.jar 在一次使用moco框架的时候,浏览器查看响应时,发现返回来的中文是乱码. 按照网上的操作,在响应结果中加上heade ...

  2. 神器| 这款软件让win系统像Mac系统一样的好用!

    每天进步一丢丢,连接梦与想 输不起的人,往往就是赢不了的人 使用过 Mac OS X 系统的朋友可能都会使用过自带的 Quick Look 快速预览功能,用鼠标选中一个文件后,再按下键盘空格键就会弹出 ...

  3. 「雅礼集训 2017 Day2」棋盘游戏

    祝各位圣诞后快乐(逃) 题目传送门 分析: 首先棋盘上的路径构成的图是一张二分图 那么对于一个二分图,先求出最大匹配,先手如果走到关键匹配点,只要后手顺着匹配边走,由于不再会出现增广路径,所以走到最后 ...

  4. Windows环境下配置robotframework

    Robot Framework安装准备 一.python3.6以上版本 安装过程中勾选“add python to path”,就可以自动配置好环境变量. 安装完成后在命令行输入python,如下图所 ...

  5. Windows中安装Linux子系统的详细步骤

    早就听说Windows中可以安装Linux子系统,体验了一下,感觉还是不错的,下面直接开始安装和配置步骤吧! 开启Windows中的配置 首先开启开发者模式 打开"所有设置"进入& ...

  6. c#数字图像处理(七)直方图匹配

    直方图匹配,又称直方图规定化,即变换原图的直方图为规定的某种形式的直方图,从而使两幅图像具有类似的色调和反差.直方图匹配属于非线性点运算. 直方图规定化的原理:对两个直方图都做均衡化,变成相同的归一化 ...

  7. .net 项目更改默认命名空间

    这个项目是我去年毕业设计做的项目,项目创建的时候由于手抖把Landlordtenant写成了 LandloRdtenant(R大写了),当时不知道如何改回来又担心改完之后报错也就没管了. 今天尝试使用 ...

  8. ROC 曲线

    Receiver Operating Characteristic (接收机操作特性曲线) 是以虚警率为横轴,以击中率为纵轴,长成如下模样: 所谓击中率(hit)是指将正样本判断为正样本的比例,而虚警 ...

  9. 探究HashMap1.8的扩容

    扩容前 扩容后 机制 else { // preserve order Node<K,V> loHead = null, loTail = null;//低指针 Node<K,V&g ...

  10. C编程规范

    目 录 1.版面... 2.命名... 3.注释... 4.源代码结构... 附录A:常见单词缩写表... 1.版面 [规则1-1] 程序块要采用缩进风格编写,缩进的空格数为4个. [规则1-2] 对 ...