设为首页 收藏本站
查看: 814|回复: 0

[经验分享] 职责链模式(Chain of Responsibility Pattern)-餐馆的故事

[复制链接]

尚未签到

发表于 2015-11-26 08:58:04 | 显示全部楼层 |阅读模式

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


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


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


DSC0000.jpg


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


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


意图


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


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


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


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


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


DSC0001.jpg


参与者


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 == &quot;农家小炒肉&quot;)
            {
                Console.WriteLine(&quot;{0}做的{1}&quot;, 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 == &quot;酸辣土豆丝&quot;)
            {
                Console.WriteLine(&quot;{0}做的{1}&quot;, name, customer.OrderName);
            }
            else
            {
                base.HandleRequest(customer);
            }
        }
    }
}

注意


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


问题


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


其它的例子


浏览器事件模型


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


击鼓传花


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


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


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




参考:


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


《UML基础、案例与应用》Joseph Schmullerhttp://www.dofactory.com/Patterns/PatternChain.aspx


来自:http://www.cnblogs.com/anderslly/archive/2008/02/28/chainofresponsibility.html

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-143674-1-1.html 上篇帖子: 使用Chef管理windows集群 | 运维自动化工具 下篇帖子: chef client注册为node
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表