博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
餐馆的故事-浅析职责链模式
阅读量:6717 次
发布时间:2019-06-25

本文共 3235 字,大约阅读时间需要 10 分钟。

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

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

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

这当中就包含了职责链模式(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);
}
}
}
 
/// 
/// 服务员不用炒菜,所以直接转发给后继者。
/// 
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.cnblogs.com/anderslly/archive/2008/02/28/chainOfResponsibility.html,如需转载请自行联系原作者。

你可能感兴趣的文章
中国太阳能续增 补贴、技术转型均受重视
查看>>
北京信息化协会人工智能专委会成立 AI产业快速腾飞
查看>>
《PostgreSQL服务器编程》一一1.9 关于缓存
查看>>
IBM芯片计划:生物是设计更高效芯片的关键
查看>>
没有这个黑客,就不会有你现在用的开源软件
查看>>
传统管理软件走在“生死边缘”,突围SaaS向死而生?
查看>>
这些数据科学技能,才是老板们最想要的
查看>>
大数据条件下政府信息化管理
查看>>
大数据+区块链将大有可为
查看>>
三大研究机构预测:6家公司吃掉80%云计算市场
查看>>
智能家居“吸金”新方式 家电或成救世主
查看>>
浙江电力使用RFID技术,有力保障电网运营
查看>>
呼叫中心管理之:让座席看见自己
查看>>
运营商全渠道建设的终极形态
查看>>
Java核心类库:内部类那点事儿
查看>>
《SAP入门经典(第5版)》——2.5 小结
查看>>
《软件建模与设计: UML、用例、模式和软件体系结构》一一1.8 软件建模和设计方法的发展...
查看>>
web 应用通用数据访问层 Fetchr
查看>>
《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.2 建立基准...
查看>>
绕过 Windows 10 Cloud 限制 成功运行 Win32 应用程序
查看>>