我们在餐馆吃饭的时候,一般都是在拿到菜单后,选择喜欢的菜,然后通知服务员。服务员会将我们的定单交给大厨,大厨可能会亲自去做这道菜,也可能安排给小厨来做,总之,我们不用担心他们没有人做菜,即使有时候等的时间长点。

下面我们来分析一下。首先,对于我们这些点菜的人来说,我们一般不了解这些厨师,我们没法找到某个具体的厨师让他去做,所以只好把请求交给服务员;然后,对于餐馆的服务员、大厨、小厨来说,他们都可以接受并处理这个请求,但很明显,他们有分工,不会一人去做所有的菜。

简单地说,顾客发送请求(点菜),餐馆的人接受请求(拿到定单),有多个人可以处理该请求(做菜),或者说履行职责,但最后只有一人处理该请求。如下图所示:

这当中就包含了职责链模式(Chain Of Responsibility,简称CoR)。

我们来看看Gof中CoR的描述:

意图

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

从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者,请求发送者不确定到底哪个对象会处理它,——我们称该请求有一个隐式的接受者(implicit receiver)。

在餐馆的例子中,顾客是请求的发送者,接受者则是服务员、大厨、小厨,他们构成了一条职责链,他们当中会一个人来处理请求。

好了,菜终于上来了,先把它吃掉吧...

现在走出餐馆,我们来看看在一般场景下,CoR的类图是:

参与者

Handler(如Employee)

——定义一个处理请求的接口;

ConcreteHandler(如Server和Chef)

——处理它负责的请求;

——可访问它的后继者(Successor);

——如果可处理该请求,处理之;否则转发给后继者;

Client

——向职责链提交请求。

适用性

1、有多个的对象可以处理一个请求,而具体的处理者在运行时自动确定;

2、希望在对接受者不了解的情况下,向多个对象的一个提交请求;

3、处理请求的对象集合需要动态指定。

示例代码

using System;
 
namespace ChainOfPatterns
{
    class Program
    {
        static void Main(string[] args)
        {
            // 餐馆工作人员
            Server server = new Server("anders");
            Chef chef = new Chef("dudu");
            AssistantChef ac = new AssistantChef("bill");
            server.SetSuccessor(chef);
            chef.SetSuccessor(ac);
 
            Customer customer = new Customer();
            // 点第一道菜
            customer.OrderName = "酸辣土豆丝";
            server.HandleRequest(customer);
 
            // 点第二道菜
            customer.OrderName = "农家小炒肉";
            server.HandleRequest(customer);
 
            Console.ReadLine();
        }
    }
 
    public class Customer
    {
        private string orderName;
 
        public string OrderName
        {
            get { return orderName; }
            set { orderName = value; }
        }
    }
 
    public abstract class Employee
    {
        protected string name;
        protected Employee successor;
 
        public Employee(string name)
        {
            this.name = name;
        }
 
        public void SetSuccessor(Employee successor)
        {
            this.successor = successor;
        }
 
        public virtual void HandleRequest(Customer customer)
        {
            if (successor != null)
            {
                successor.HandleRequest(customer);
            }
        }
    }
 
    /// <summary>
    /// 服务员不用炒菜,所以直接转发给后继者。
    /// </summary>
    public class Server : Employee
    {
        public Server(string name) : base(name)
        {
        }
    }
 
    public class Chef : Employee
    {
        public Chef(string name) : base(name)
        {
        }
 
        public override void HandleRequest(Customer customer)
        {
            if (customer.OrderName == "农家小炒肉")
            {
                Console.WriteLine("{0}做的{1}", name, customer.OrderName);
            }
            else
            {
                base.HandleRequest(customer);
            }
        }
    }
 
    public class AssistantChef : Employee
    {
        public AssistantChef(string name) : base(name)
        {
        }
 
        public override void HandleRequest(Customer customer)
        {
            if (customer.OrderName == "酸辣土豆丝")
            {
                Console.WriteLine("{0}做的{1}", name, customer.OrderName);
            }
            else
            {
                base.HandleRequest(customer);
            }
        }
    }
}

注意

如果我们运气很差,点了一个没有存货的菜,那么不管是服务员还是大厨、小厨都没法处理了。也就是说,对于一个请求,可能没有任何接受者会处理它。

问题

我还想到一个问题,如果一道菜很复杂,需要大厨和小厨一起做,该怎么办呢?望各路高手指点迷津 :)

其它的例子

浏览器事件模型

假设我们的HTML页面上有一个<div />,它又包含了一个<input />按钮,对于按钮的click事件来说,在IE中它的触发顺序为从最特定的事件目标(button)道最不特定的事件目标(document对象)。input,div,body到document,它们也构成了一条职责链。

击鼓传花

击鼓传花是一种热闹而又紧张的饮酒游戏。在酒宴上宾客依次坐定位置,由一人击鼓,击鼓的地方与传花的地方是分开的,以示公正。开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在某人手中,则该人就得饮酒。

看起来,酒宴上的宾客构成了一条链。但我认为这是CoR的一个反面例子。对于每一轮具体的游戏来说,这些宾客唯一能做的事情就是将花束传递(转发给后继者),没有谁能够主动停下来,而能够处理请求的人(击鼓者)到底是谁的后继者呢?这个并不确定,职责链如何构建呢?

另外,建议看一看下面两篇文章中高手的论述:职责链模式在开发中的应用,手拉手就是职责链吗?

参考:

《设计模式-可复用面向对象软件的基础》 Gof

《UML基础、案例与应用》Joseph Schmuller

http://www.dofactory.com/Patterns/PatternChain.aspx

本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2008/02/28/chainOfResponsibility.html,如需转载请自行联系原作者。

餐馆的故事-浅析职责链模式相关推荐

  1. 十八、职责链模式-推卸责任,不关我的事,我不管!#和设计模式一起旅行#

    不在其位,不谋其政! –出自<论语·泰伯> 故事背景 在现实世界中,有很多情况下会遇到一些推卸责任的场景,比如要办理一件事的时候,被告诉你要去做个做这个事情,但是去了这个地方,确告诉要到另 ...

  2. 职责链模式之真假美猴王

    孙悟空最终还是没有能逃脱如来的手掌心,因缘注定,皈依佛门,虽没有了做齐天大圣是的逍遥快活,也没有大闹天宫时的轰轰烈烈,但是现在有了更重要的一项任务,那就是普度众生,< 西游记>第五十七回, ...

  3. JAVA 设计模式—————— 命令模式和职责链模式

    学习 Netty 前的准备工作!! 这里,还是先来复习一下 OOP (面向对象)的七大原则: 开闭原则:对扩展开放,对修改关闭 里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立. 依赖倒置原 ...

  4. 设计模式之职责链模式(Chain of Responsibility)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  5. 职责链模式里面必须要知道的事情

    为什么80%的码农都做不了架构师?>>>    职责链模式里面必须要知道的事情 用java web开发的很多同学很容易沉迷于各种框架的使用技巧,而忽略servlet的一些细节.对很多 ...

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

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

  7. Python设计模式-职责链模式

    Python设计模式-职责链模式 代码基于3.5.2,代码如下; #coding:utf-8 #职责链模式class Handler():def __init__(self):self.success ...

  8. 设计模式之职责链模式、减小了因为分支带来的耦合

    1. 定义 职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一 ...

  9. 22.Chain of Responsibility(职责链)模式

    技术交流QQ群:1027579432,欢迎你的加入! 1.Chain of Responsibility(职责链)模式动机 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个 ...

最新文章

  1. 444牛X的日常口语
  2. 360安全卫士核心改名ZhuDongFangYu.exe
  3. 什么是 IP 地址?
  4. ionic cordova 常用命令
  5. JSP(九大内置对象)
  6. 思路初探:采用c#实现pdf转ofd
  7. 简单实现内外网自由切换、指定网卡上网
  8. android 手机 屏幕镜像,怎样将手机屏幕镜像到电视上(屏幕镜像连接方式)
  9. 遇到一个很冷门的bug(java.lang.NoSuchMethodException问题原因及解决办法)
  10. FFMPEG学习【libavfilter】(二)
  11. GStreamer和gst-omx插件
  12. 真•神器:Desmos 心形曲线x4
  13. 安装python3.5.0出现0x80072eff错误_我在网上用WINDOWS UPDATE更新WINDOWS,出现错误:0x80072EFF,该怎么办?...
  14. 【单片机】51单片机使用总结
  15. win无线网卡怎么进入监听模式_网卡灯正常,但却不能连入网络该如何解决?
  16. WebDAV之葫芦儿•派盘+RS文件管理器
  17. cesium 之三维场景展示篇(附源码下载)
  18. Github 之提交代码
  19. 常熟理工学院计算机专业排名2015,2019年常熟理工学院优势专业排名及分数线
  20. html5 css3 jquery 画板

热门文章

  1. js正则表达式限制文本框只能输入数字,小数点,英文字母
  2. MachineLearning(2)-图像分类常用数据集
  3. Pytorch(3)-数据载入接口:Dataloader、datasets
  4. MySQL吉连_Learn Jdbc : Java, Jdbc, Odbc
  5. c++ memory 头文件详细介绍
  6. 在pycharm中使用conda虚拟环境(conda虚拟环境是已经创建好的),解决python安装包文件很费劲的问题
  7. 能让你成为更优秀程序员的10个C语言资源
  8. 264 参考帧 list0 list1
  9. FormsAuthenticationTicket基于forms的验证
  10. mysql 索引的统计