一、引言

今天我们开始讲“行为型”设计模式的第八个模式,该模式是【职责链模式】,英文名称是:Chain of Responsibility Pattern。让我们看看现实生活中的例子吧,理解起来可能更容易。我们看看某公司的采购流程吧。某公司的规章制度规定,采购原材料的总价在5万之内,只需要经理级别的人批准即可,采购总价大于5万小于10万的则需要财务经理进行批准,总价大于10万小于30万的需要总经理批准,而总价大于30万的则需要通过董事会会议讨论决定。对于这样一个需求,最直接的方法就是设计一个方法,该方法接受的参数是采购的总价,然后在这个方法内对价格进行判断,然后针对不同的条件交给不同级别的角色去处理,如果情况就是这样,不变了,这样做很好,没问题。如果我们又有新的条件要增加该怎么办呢?我们不得不去修改原来设计的方法来再添加一个条件判断,让本已多重if-else判断语句更多了,这样的设计显然违背了“开放-关闭”原则。这时候,我们可以采用职责链模式来解决这样的问题。

二、职责链模式的详细介绍

2.1、动机(Motivate)

在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合。如何使请求的发送者不需要指定具体的接受者,让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。

2.2、意图(Intent)

避免请求发送者与接收者耦合在一起,让多个对象都有可能接受请求,将这些对象连接成一条链,并且沿着这条链传递请求,知道有对象处理它为止。                                      ——《设计模式》GoF

2.3、结构图(Structure)

2.4、模式的组成
    
    可以看出,在职责链模式的结构图有以下角色:

(1)、抽象处理者角色(Handler):抽象处理者定义了一个处理请求的接口,它一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个自类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。

    (2)、具体处理者角色(ConcreteHandler):具体处理者是抽象处理者的子类,它可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。

2.5、职责链模式的代码实现

在现实生活中,职责链模式的例子也是很多的,例如:公司的请假流程就是一个很好的职责链模式的例子,如果请假半天,只要告诉本部门经理就可以了;如果请假7天或者以上必须人事总监批准;如果请假15天以上,那就要经过总裁批准了。还有类似的例子就是采购的流程,其流程也是职责链模式很好的体现,采购的金额不同,需要批准的人员也不同,比如:部门采购1万元的纸品,只要部门领导签批就可以,如果要采购大于1万小于5万的物品,那就需要财务经理签批了,如果采购30万的原材料或者物品,那就需要总裁或者类似角色才能审批了。接下来我们就以采购的实例来说明职责链模式。实现代码如下:

 namespace ChainOfResponsibility
{
// 采购请求
public sealed class PurchaseRequest
{
// 金额
public double Amount { get; set; } // 产品名字
public string ProductName { get; set; } public PurchaseRequest(double amount, string productName)
{
Amount = amount;
ProductName = productName;
}
} //抽象审批人,Handler---相当于“抽象处理者角色”
public abstract class Approver
{
//下一位审批人,由此形成一条链
public Approver NextApprover { get; set; } //审批人的名称
public string Name { get; set; } public Approver(string name)
{
this.Name = name;
} //处理请求
public abstract void ProcessRequest(PurchaseRequest request);
} //部门经理----相当于“具体处理者角色” ConcreteHandler
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}的采购计划!", this.Name, request.ProductName);
}
else if (NextApprover != null)
{
NextApprover.ProcessRequest(request);
}
}
} //财务经理---相当于“具体处理者角色”ConcreteHandler
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}的采购计划!", this.Name, request.ProductName);
}
else if (NextApprover != null)
{
NextApprover.ProcessRequest(request);
}
}
} //总裁---相当于“具体处理者角色” ConcreteHandler
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} 的采购计划!", this.Name, request.ProductName);
}
else
{
Console.WriteLine("这个采购计划的金额比较大,需要一次董事会会议讨论才能决定!");
}
}
} class Program
{
static void Main(string[] args)
{
PurchaseRequest requestDao = new PurchaseRequest(8000.0, "单刀5把");
PurchaseRequest requestHuaJi = new PurchaseRequest(10000.0, "10把方天画戟");
PurchaseRequest requestJian = new PurchaseRequest(80000.0, "5把金丝龙鳞闪电劈"); Approver manager = new Manager("黄飞鸿");
Approver financial = new FinancialManager("黄麒英");
Approver ceo = new CEO("十三姨"); // 设置职责链
manager.NextApprover = financial;
financial.NextApprover = ceo; // 处理请求
manager.ProcessRequest(requestDao);
manager.ProcessRequest(requestHuaJi);
manager.ProcessRequest(requestJian); Console.ReadLine();
}
}
}

模式的代码如上,很简单,备注很清楚,慢慢品味一下就知道其中道理了。

三、职责链模式的实现要点:

Chain of Responsibility模式的应用场合在于“一个请求可能有多个接受者,但是最后真正的接受者只有一个”,只有这时候请求发送者与接受者的耦合才有可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦,从而更好地应对变化。

  应用了Chain of Responsibility模式后,对象的职责分派将更具灵活性。我们可以在运行时动态添加/修改请求的处理职责。

  当我们要新增一个DHandler处理请求,就不需再改原来的代码了,遵从了开放封闭原则。这样我们的程序就更赋予变化,更有变化的抵抗力。Handler类本身继承自BaseHandler类型,又包含了一个BaseHandler类型的对象,这点类似Decorator模式。

  如果请求传递到职责链的末尾仍得不到处理,应该有一个合理的缺省机制。这也是每一个接受对象的责任,而不是发出请求的对象的责任。

(1)、职责链模式的主要优点有:

1】、降低耦合度:职责链模式使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需知道该请求会被处理即可,接受者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,有客户端负责链的创建。

2】、可简化对象的相互连接:接受者对象仅需维持一个指向其后继者的引用,而不需维持它对所有的候选处理者的引用。

3】、增强给对象指派职责的灵活性:在给对象分派职责时,职责链可以给我们带来更多的灵活性。可以通过在运行时对该连进行动态的增加或修改处理一个请求的职责。

4】、增加新的请求处理类很方便:在系统中增加一个新的请求处理者无需修改原有系统的代码,只需要在客户端重新建链即可,从这一点看来是符合“开闭原则”的。

 (2)、职责链模式的主要缺点有:

1】、在找到正确的处理对象之前,所有的条件判定都要执行一遍,当责任链过长时,可能会引起性能的问题。

2】、可能导致某个请求不被处理。

3】、客户端需要组装这个链条,耦合了客户端和链条的组成结构,可以把这个在客户端的组合动作提到外面,通过配置来做,会更好点。

(3)、在下面的情况下可以考虑使用职责链模式:

1】、一个系统的审批需要多个对象才能完成处理的情况下,例如请假系统等。

2】、代码中存在多个if-else语句的情况下,此时可以考虑使用责任链模式来对代码进行重构

3】、有多个对象可以处理同一个请求,具体哪个对象处理该请求有运行时刻自动确定。客户端只需将请求提交到链上,无须关心请求的处理对象是谁以及它是如何处理的。

4】、不明确指定接受者的情况下,向多个对象中的一个提交一个请求。请求的发送者与请求者解耦,请求将沿着链进行传递,寻求响应的处理者。

5】、可动态指定一组对象处理请求。客户端可以动态创建职责链来处理请求,还可以动态改变链中处理者之间的先后次序

四、.NET 职责链模式的实现

这个模式在Net框架中的实现不多,我感觉这个模式的使用场景更多的是在业务系统总才会有更大的用处。这种模式在处理UI的消息时很常用,但实际上Windows消息循环还是硬编码的结构。因为效率上的考虑,Windows消息循环是哪个对象有一个请求,则直接到达处理函数的地址。如果链条上的对象多了,而真正处理的函数在链条后部分,效率会很低下。因此我们在使用这种模式的时候更适合业务流程,即对性能要求不是特别高的情况更加常用。

五、总结

终于写完了,这个模式并不是很难,在现实生活中也能很容易的找到对应的实例。这个模式也是为了解耦,解耦请求的发送者和接受者,当有新的需求的时候更容易变化,让我们的代码更符合面向对象OO的设计。

C#设计模式之二十一职责链模式(Chain of Responsibility Pattern)【行为型】的更多相关文章

  1. 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)

    责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...

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

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

  3. C#设计模式——职责链模式(Chain Of Responsibility Pattern)

    一.概述 在软件开发中,某一个对象的请求可能会被多个对象处理,但每次最多只有一个对象处理该请求,对这类问题如果显示指定请求的处理对象,那么势必会造成请求与处理的紧耦合,为了将请求与处理解耦,我们可以使 ...

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

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

  5. 职责链模式(chain of responsibility Pattern)

    职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. •Handler: 抽象处理者:定义出一个 ...

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

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

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

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

  8. 二十四种设计模式:责任链模式(Chain of Responsibility Pattern)

    责任链模式(Chain of Responsibility Pattern) 介绍为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求.将这些对象连成一条链,并沿着这条链传递该请求,直 ...

  9. 职责链模式(Chain of Responsibility)(对象行为型)

    1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就推卸给另外个一个部门(对象).至于到底谁来解决这个问题呢?政府部门就是为了可以避免屁民的请求与 ...

随机推荐

  1. JMeter基础教程3:脚本录制篇

    对于一些JMeter初学者来说,录制脚本可能是最容易掌握的技能之一.虽然我不建议录制性能脚本(因为录制的脚本比较混乱,必须要通过二次处理才可正常使用),但有时做总比不做要好,是吧?下面我们详细介绍使用 ...

  2. axios在vue中的简单配置与使用

    一.axios 简介 axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:https://hzzly.github.io/2017/03/12/ ...

  3. RabbitMQ之比较好的资料

    http://mysql.taobao.org/index.php/Rabbitmq http://www.cnblogs.com/me-sa/archive/2012/10/17/rabbitmq_ ...

  4. javascript第七章--DOM

    ① 节点层次 ② DOM操作技术

  5. 以太网接口芯片W5300使用说明

    一.芯片简介 引用百度百科对芯片的一个简介,我就不再赘述. W5300的目标是在高性能的嵌入式领域,如多媒体数据流服务.与WIZnet现有的芯片方案相比较,W5300在内存空间和数据处理能力等方面都有 ...

  6. 自己动手修改Robotium代码(下)

    public void takeScreenshot(){   View decorView = viewFetcher.getRecentDecorView(viewFetcher.getWindo ...

  7. react-router 3 中的 useRouterHistory(createHistory) 到了 react-router 4 变成了什么?

    react-router 3 文档: https://github.com/ReactTraining/react-router/blob/v3/docs/API.md react-router 4 ...

  8. osap一站式分析模型

    运营系统分析平台技术设计: 项目定义于运营系统关键指标的数据分析 关键代码描述: HiveWriter 主要用于写hive表抽象,包括加分区,写hive表,写success文件: import org ...

  9. 照虎画猫写自己的Spring——自定义注解

    Fairy已经实现的功能 读取XML格式配置文件,解析得到Bean 读取JSON格式配置文件,解析得到Bean 基于XML配置的依赖注入 所以,理所当然,今天该实现基于注解的依赖注入了. 基于XML配 ...

  10. Ztree改版 - 将图标字体化 - fontAwesome

    引言 ps:小白可以一看,大神勿打~ 用过 ztree 的盆友们都知道,ztree 功能强大,就功能上来说,追求着“无处不按钮”的体验,但好用不好看.可能有朋友说:“我这棵树只有我自己看,够用就行” ...