`
wbj0110
  • 浏览: 1612298 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

设计模式之责任链模式(转)

阅读更多

一. 写在前面的

这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式。

因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理。所以希望各位多多指教。

二. 什么是链

image

文章伊始,先让我们了解这个最基本的概念,什么是链。

我给链下了这样的定义:

1. 链是一系列节点的集合。

2. 链的各节点可灵活拆分再重组。

三. 何为职责链

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

图如下:

chain

UML很简单,让我们先来看一个简单的例子。

四. 职责链模式应用之请假管理

请假这个事情,相信每个人都不陌生。

我们公司是个相对很宽松的公司。

在公司里,如果你的请假时间小于0.5天,那么只需要向项目经理打声招呼就OK了。

如果超过了0.5天,但是还小于2天,那么就要去找人事部处理,当然,这就要扣工资了。

如果超过了2天,你就需要去找总经理了,工资当然也玩完了。

那么,对于我们来说,这个流程就是这样的。

image

也就是这样一个过程,你需要和你的直接上级——项目经理去打交道,最终可能是项目经理给你回邮件,

可能是人事部给你回邮件,也可能是总经理给你回邮件。内部的过程其实应该是个黑盒子,

你并不知道内部的消息是如何处理的。你需要找到的,只是你想要第一个交付的对象而已。

无标题

那么我们的代码应该是这样的。

首先我们要写一个请求的类。

class Request {
 private int day;
 private string reason; 
public int Day { get return day; } set { day = value; } } public string Reason { get return reason; } set { reason = value; } } publicRequest(int day, string reason) { this.day = day; this.reason = reason; } }
接下来看下请求相应者,他们有两个核心方法,一个是相应操作,一个是选择继任者。
abstract class Boss private string name; public string Name { get return name; } set { name =value; } } private Boss successor; public Boss Successor { get return successor; } set { successor =value; } } public Boss(string name) { this.name = name; } public abstract bool PassRequest(Requestrequest); } class PM:Boss public PM(string name) : base(name) { } public override boolPassRequest(Request request) { int day = request.Day; string reason = request.Reason; if (day <= 0.5) { return true; } return Successor.PassRequest(request); } } class HR:Boss public HR(string name) :base(name) { } public override bool PassRequest(Request request) { int day = request.Day; stringreason = request.Reason; if (day > 0.5&&day<=2) { return true; } returnSuccessor.PassRequest(request); } } class Manager Boss public Manager(string name) : base(name) { } public override bool PassRequest(Request request) { int day = request.Day; string reason = request.Reason; if (reason.Equals("正当理由")) { return true; } return false; } }

那么我们调用的时候就很简单了!

static void Main(string[] args) { Request request = new Request(3, "非正当理由"); Boss pm = newPM("pm"); Boss hr = new HR("hr"); Boss manager = new Manager("manager"); pm.Successor = hr; hr.Successor = manager; bool pass = pm.PassRequest(request); Console.Write(pass); }

五. 灵活在哪?

让我们来看下职责链究竟灵活在哪?

1. 改变内部的传递规则。

无标题

在内部,项目经理完全可以跳过人事部到那一关直接找到总经理。

每个人都可以去动态地指定他的继任者。

2. 可以从职责链任何一关开始。

如果项目经理不在,那么完全可以写这样的代码:

static void Main(string[] args) { Request request = new Request(3, "非正当理由"); Boss pm = newPM("pm"); Boss hr = new HR("hr"); Boss manager = new Manager("manager"); pm.Successor = hr; hr.Successor = manager; //bool pass = pm.PassRequest(request); bool pass = hr.PassRequest(request);Console.Write(pass); }

 

3. 我们来比较一下,用职责链和不用职责链的区别:

image

这是不用职责链我们的结构,我们需要和公司中的每一个层级都发生耦合关系。

如果反映在代码上即使我们需要在一个类中去写上很多丑陋的if….else语句。

如果用了职责链,相当于我们面对的是一个黑箱,我们只需要认识其中的一个部门,然后让黑箱内部去负责传递就好了。

六. 职责链 != 链表

很多人都愿意把职责链和链表混为一谈,确实,从字面意思上理解,链,链表,很像。可是他们一样么?

他们区别在哪里:

让我们看一个链表的典型结构:

image

让我们来看一下链表的典型特征:

1. 链表是一个链状结构,每个节点有一个next属性去指向他的下一节点。

2. 链表有一个Header节点,然后用户每次必须通过头节点,然后去遍历寻找每一个节点。

3. 链表遍历操作的复杂度是O(n),但是插入和删除指定节点的复杂度是常数级。

让我们来着重看这第二点:

我们来想想在文章开始时我们画出的那个链,一个链,我们可以从头将他拿起,也可以从中间将他拿起:

image

也就是说我们用户可以去访问节点中的任何一个节点作为开始节点,这就是链表与职责链不同的地方。

七. 职责链的扩展——树状链结构

职责链中,我们之前看到的都是一些单链结构,但是其实在很多情况下,每一个节点都对应着很多其他的部分。

image 

那么这样,我们的每一个节点都可以使用一个List来维护他节点的下一节点,甚至可以用组合模式来分别设计每一节点。

八. 由法律想到——职责链的兜底条款

仔细想想法律条文,尤其是刑法,经常可以看到这样的条文:

1. 如果*********,则处以拘役处分。

2. 如果*********,则处以有期徒刑一年到十年。

3. 如果*********,则处以有期徒刑十年以上。

4. 如果*********,则**********。

5. 如果以上条件皆不满足,则*****************。

其实最后一条就叫做法律的兜底条款。这给了法官很大的自由裁量权,在一定程度上也降低了犯罪分子钻法律空子的可能性。

在我们的职责链中,如果不存在这样的兜底条款,那么用户如果不从首节点开始访问,那么就很可能出现异常的情况。于是我们应该为职责链设置一个默认的条款:

image

这样的话,任何一个处理无论如何访问,都能得到一个正常的处理。

九. 职责链的缺点

让我们继续回到上面的例子,我们发现,其实当请假时间超过2天的时候,PM和HR其实没有做任何的事情,而只是做了一个传递工作。

而传递工作之后,他们就成了垃圾对象。

也就是说,他们在实际的处理中,并没有发挥任何的作用。

那么当这个链结构比较长,比较复杂的话,会产生很多的内存垃圾对象。

这也就是职责链的最大缺点之所在。

十. 职责链的乱用

在和其他的人的讨论中,我发现他们的观点是:

只要一者传一者,那么就要用职责链。在我们的项目中,他们这样去用:

abstract class DBHelper { } interface IRequestHandler { IDBHelper ReturnHelper(string dbName); } classRequestHandler:IRequestHandler private RequestHandler successor; public RequestHandler Successor {get return successor; } set { successor = value; } } public abstract IDBHelper ReturnHelper(stringdbName); } class SQLHelper DBHelper { } class OracleHelper DBHelper { } class DB2Helper DBHelper{ } class SQL RequestHandler public override IDBHelper ReturnHelper(string dbName) { if(dbName.Equals("SQL Server")) { return new SQLHelper(); } return Successor.ReturnHelper(dbName); } }class Oracle RequestHandler public override IDBHelper ReturnHelper(string dbName) { if(dbName.Equals("Oracle")) { return new OracleHelper(); } return Successor.ReturnHelper(dbName); } }class DB2 RequestHandler public override IDBHelper ReturnHelper(string dbName) { if(dbName.Equals("DB2")) { return new DB2Helper(); } return new SQLHelper(); } }

 

这样的话,每个类相当于只负责一个操作。

那么我们如何改进呢?第一,我们可以用一个工厂来实现。另外,我们可以用表驱动的方式来解决问题。

十一. 表驱动改进职责链

表驱动(Table driven),其实就是指用查表的方式来获取值。

那么我们用标驱动法来改进上面的例子:

class HelperRequest private Dictionary<StringDBHelper> dic = new Dictionary<stringDBHelper>();public void Add(string name,DBHelper helper) { dic.Add(name, helper); } public DBHelperGetHelper(string name) { DBHelper helper; bool temp = dic.TryGetValue(name, out helper); if (temp) {return helper; } return null; } }

我想一个没有学过设计模式的人都会这样写的。一个学过设计模式很多年的人也会这样写的。

而怕的就是为了模式而模式,为了职责链而职责链了。

十二. 职责链在java script中的应用

我们想象这样一种情况:

image

我们都知道,在ASP.NET 的 Webform模型中页面是以控件树的形式去组织的。那么我们用右键点击其中的一个页面,那么这个事件就会找离他最近的控件,如果不存在,那么就去找他的父控件,如此递归下去,直到找到为止。

这其实就是一种职责链的体现!

十三. 深析职责链的使用

职责链模式不能乱用,否则非常容易变成因为模式而模式的反例。

下面是我归纳出来的一些关于职责链方面的使用规则,只是个人的意见,还希望大家指教。

1, 如果存在N对N,或者是一般的常规线性关系,那么我们完全可以用表驱动来取代职责链。

2, 对象本身要经过什么处理是通过每个链上元素通过运行态来决定的,决定的因素是取决于对象的属性或者一些其他方面的策略。

3, 用户无论是从哪一个节点作为他的请求头节点,最终用户都可以得到一个请求的反馈。

4, 应怪怪建议,补充同级的处理!职责链并非是严格的上下级的传递,其中也包括同级的传递,职责链一样可以在同级之间做传递。

例如,继续用我们上面请假的那个做例子,也许我们公司有两个HR,事实上也是这样的,我们把前台“MM”也美称为人力资源部:

static void Main(string[] args) { Request request = new Request(3, "非正当理由"); Boss pm = newPM("pm"); Boss hr1 = new HR("Real HR"); Boss hr2 = new HR("QiantaiMM"); Boss manager = newManager("manager"); pm.Successor = hr1; hr1.Successor = hr2; hr2.Successor = manager; bool pass = pm.PassRequest(request); Console.Write(pass); }

其实这样也未尝不可。有人也许会说,那么这样的同样一个类的两个对象又有什么意义呢?

那么我们不妨去试着这样改造这个HR的类。

enum HRType { RealHR, Qiantai } class HR:Boss private HRType type; public HR(string name,HRTypetype) : base(name) { this.type = type; } public override bool PassRequest(Request request) { int day = request.Day; if (day>=0.5&&day<2) { switch (type) { case HRType.RealHR: //扣工资 return truebreak;case HRType.Qiantai: //不扣工资 return truebreak; } } return Successor.PassRequest(request); } }

这样,因为前台MM容易说话,很可能他就不去扣你的工资,如果你去先找的HR,那么你这天的工资就报销了。

同理,我们一样可以让他们的职责细化,比如说Real Hr负责0.5天到1天的,而Qiantai去负责1天到2天的,也未尝不可。

总之,职责链并非是单一的上下级的传递,一样可以实现同级的传递。

 

十四. 职责链总结

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

今天就写到这了,希望大家多多指教。

分享到:
评论

相关推荐

    设计模式之责任链模式Java实现

    责任链模式(Chain of Responsibility)是一种行为设计模式,它允许将请求沿着处理者对象的链进行传递,直到某个对象能够处理这个请求为止。在Java中,我们可以通过接口和类的组合来实现这种模式。让我们深入探讨...

    设计模式之责任链模式源码

    责任链模式是设计模式中的一种行为模式,它允许在对象之间建立一条处理请求的链条,每个对象都包含对请求的处理逻辑,以及将请求传递给下一个对象的能力。这种模式使得请求可以在链上的对象之间传递,直到被某个对象...

    设计模式之责任链模式

    责任链模式是一种行为设计模式,它允许我们把请求沿着处理者链进行传递,直到某个处理者处理这个请求。这种模式让请求的发送者和接收者解耦,因为发送者无需知道哪个对象会处理请求,接收者也不知道其他处理者的存在...

    JAVA 设计模式 工厂模式 代理模式 迭代模式 责任链模式 源码

    4. **责任链模式**:责任链模式是行为型设计模式,它使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合。在这个模式中,请求沿着处理者链进行传递,每个处理者都有机会处理请求,或者将请求传递...

    JAVA设计模式之行为模式 责任链模式和状态模式

    本篇将探讨两种重要的行为设计模式:责任链模式(Chain of Responsibility Pattern)和状态模式(State Pattern)。 **责任链模式**是一种使多个对象都有机会处理请求的模式,避免请求发送者与接收者之间的耦合。在...

    java设计模式之责任链模式

    在“java设计模式之责任链模式”的主题中,我们可以深入探讨如何在实际项目中应用责任链模式,包括但不限于以下方面: 1. **代码结构优化**:通过责任链模式,可以使代码结构更加清晰,降低类间的耦合度。 2. **可...

    设计模式-责任链模式

    责任链模式是一种行为设计模式,它允许我们把请求沿着处理者对象的链式结构进行传递,直到某个对象处理这个请求。这种模式使得我们能够将请求的发送者与接收者解耦,同时也允许在运行时动态地改变处理顺序或添加新的...

    设计模式之责任链模式(Chain)

    责任链模式是一种行为设计模式,它的核心思想是将请求的发送者和接收者解耦,通过将多个处理对象串联成一个处理链,使得请求沿着这个链进行传递,直到被某个对象处理。这种模式使得系统更加灵活,可以在运行时动态...

    Java 经典设计模式讲解以及项目实战

    2 责任链模式 3 策略模式 4 模板方法模式 5 工厂方法模式 6 抽象工厂模式 7 建造者模式 8 代理模式 9 装饰模式 10 原型模式 11 委派模式 12 适配器模式 设计模式综合运用 1 门面+模版方法+责任链+策略 2 门面+模版...

    设计模式之责任链模式程序

    一、责任链模式 现有 “战士”、“班长”、“排长”、“连长”,“营长”五种角色,当有人要请假时要进行以下处理 1.只能是下级象上级请假(如“排长”只能向“连长请假”) 2.班长可以批准1天内的假期,排长批5天,...

    【设计模式】之责任链模式1

    责任链模式是一种行为设计模式,它允许将请求沿着处理者对象的链进行发送,而接收者可以在链中的任何位置处理该请求。这种模式的核心思想是将处理请求的对象组织成一个链条,每个对象(节点)都包含对下个处理者的...

    Android编程设计模式之责任链模式详解

    责任链模式是一种行为设计模式,它的核心思想是将一系列处理请求的对象串联成一条链,当一个请求到来时,会沿着这条链逐个处理,直到某个对象能够处理该请求为止。这种模式有效地解耦了发送请求的客户端和具体的处理...

    设计模式C++学习之责任链模式(Chain of Responsibility)

    责任链模式(Chain of Responsibility)是一种行为设计模式,它允许将请求沿着处理者对象的链进行传递,直到某个对象能够处理这个请求。这种模式的主要优点是解耦了发送者和接收者之间的关系,使得系统更加灵活,...

    c++-设计模式之责任链模式(Chain of Responsibility Pattern)

    责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许将请求的发送者和接收者解耦。通过将请求沿着处理链传递,直到有对象处理该请求为止,这种模式避免了请求发送者与具体处理者之间的紧...

    设计模式的责任链模式的例子

    责任链模式(Chain of Responsibility Pattern)是设计模式中的一种行为模式,它的主要目的是将请求的发送者和接收者解耦,使得多个对象有机会处理这个请求,形成一条责任链。在这个链上,请求会沿着链传递,直到有...

    管道设计模式、责任链模式、单例模式

    压缩包里是我自己写的管道模式、单例模式的代码;你需要copy到你自己eclipse建的工程文件中。另外,我把我的代码说明,写在了readme.txt文件里,偷懒以及求快的人看看...如果有问题,可留言。另外我分数高,但绝对有...

    spring责任链模式详解

    责任链模式是软件设计模式中的一种行为模式,它允许将请求沿着处理者对象的链进行传递,直到某个对象处理该请求。在Spring框架中,责任链模式被广泛应用于AOP(面向切面编程)和事件处理等场景。下面将详细阐述责任...

Global site tag (gtag.js) - Google Analytics