餐館的故事-淺析職責鏈模式

我們在餐館吃飯的時候,一般都是在拿到菜單后,選擇喜歡的菜,然后通知服務員。服務員會將我們的定單交給大廚,大廚可能會親自去做這道菜,也可能安排給小廚來做,總之,我們不用擔心他們沒有人做菜,即使有時候等的時間長點。

下面我們來分析一下。首先,對于我們這些點菜的人來說,我們一般不了解這些廚師,我們沒法找到某個具體的廚師讓他去做,所以只好把請求交給服務員;然后,對于餐館的服務員、大廚、小廚來說,他們都可以接受并處理這個請求,但很明顯,他們有分工,不會一人去做所有的菜。

簡單地說,顧客發送請求(點菜),餐館的人接受請求(拿到定單),有多個人可以處理該請求(做菜),或者說履行職責,但最后只有一人處理該請求。如下圖所示:

CoR

這當中就包含了職責鏈模式(Chain Of Responsibility,簡稱CoR)。

我們來看看Gof中CoR的描述:

意圖

使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞請求,直到有一個對象處理它為止。

從第一個對象開始,鏈中收到請求的對象要么親自處理它,要么轉發給鏈中的下一個候選者,請求發送者不確定到底哪個對象會處理它,——我們稱該請求有一個隱式的接受者(implicit receiver)。

在餐館的例子中,顧客是請求的發送者,接受者則是服務員、大廚、小廚,他們構成了一條職責鏈,他們當中會一個人來處理請求。

好了,菜終于上來了,先把它吃掉吧...

現在走出餐館,我們來看看在一般場景下,CoR的類圖是:

CoR2

參與者

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,如需轉載請自行聯系原作者。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/453436.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/453436.shtml
英文地址,請注明出處:http://en.pswp.cn/news/453436.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JDBC數據對象存儲

一&#xff1a;將查詢的結果生成對象&#xff0c;儲存在數組中。 1 package day31;2 3 import java.sql.Connection;4 import java.sql.PreparedStatement;5 import java.sql.ResultSet;6 import java.sql.SQLException;7 import java.util.ArrayList;8 9 public class java_ob…

個人工作13年的一些人生真實領悟

此文不定期的更新&#xff0c;想起來就寫一些&#xff0c;我都忘了我曾經會過什么了。你可能會在許多的文章里看到類似的&#xff0c;但這些是我個人的真實體會。 1 技術服從于業務 此問題以前的一個文章提過&#xff0c;不再多說。 適用于大多數對技術的盲目崇拜者。在絕大…

matlab非齊次方程組的通解,用matlab求非齊次線性方程組的通解?

先向大家介紹一下非齊次線性方程組。所謂非齊次線性方程組就是方程組等號右邊的常數項不全為零的線性方程組。全部等于零時&#xff0c;就稱為齊次線性方程組。下面我們就講解一下如何利用matlab快速求非齊次線性方程組的通解。工具/材料matlab電腦操作方法01線性方程組Axb的求…

Linux 終端仿真程序Putty

PuTTY是一個Telnet、SSH、rlogin、純TCP以及串行接口連接軟件。較早的版本僅支持Windows平臺&#xff0c;現在的版本中開始支持各類Unix平臺。 用linux作為桌面系統&#xff0c;身為工程師很多時候需要通過Telnet、SSH協議進行遠程管理&#xff0c;通過串口進行設備配置。Putty…

Mysql 數據庫水平分表 存儲過程

數據庫存儲量達到一定程度的時候&#xff0c;就需要進行分表以減輕檢索的消耗。 常用的分表方式包括水平和垂直分表。本次進行的是按照uid進行水平分表。 ##分表思路&#xff1a; 水平分表平均的將數據按照特定方式分配到多個表中。理論上每個表的訪問頻次和數據量都是同一水平…

中國架構師,名符其實有多少?

先說一下讀后感&#xff1a;我前段時間去過幾個公司面試架構師&#xff0c;要求還是蠻高的&#xff0c;要熟悉大數據量處理&#xff0c;要熟悉高并發&#xff0c;要熟悉XX體系架構&#xff0c;要能在關鍵技術上實現突破。總之&#xff0c;架構錯了&#xff0c;就啥都錯了。呵呵…

粗識靜態鏈表

為了彌補鏈表在內存分配上的不足&#xff0c;出現了靜態鏈表這么一個折中的辦法。靜態鏈表比較類似于內存池&#xff0c;它會預先分配一個足夠長的數組&#xff0c;之后鏈表節點都會保存在這個數組里&#xff0c;這樣就不需要頻繁的進行內存分配了。 當然&#xff0c;這個方法的…

php用date語句獲取時間,關于php date()函數獲取時間的設置和使用方法

date()函數是PHP自帶的時間函數&#xff0c;可以獲取當前服務器的時間echo date(Y-m-d H:i:s); //輸出:2020-05-18 11:02:35date()函數中可以使用的字母含義&#xff1a;a-"am"(上午)或者"pm"(下午)A-"AM"或者"PM"Y-年&#xff0c;顯示…

Django_form補充

問題1: 注冊頁面輸入為空&#xff0c;報錯&#xff1a;keyError&#xff1a;找不到passworddef clean(self): print("---",self.cleaned_data) # if self.cleaned_data["password"]self.cleaned_data["repeat_password"]: …

WF4.0:NativeActivity中的錯誤處理

備注&#xff1a;這篇文章的使用環境是.NET framework 4.0 RC 1 在WF4中創建native活動時&#xff0c;NativeActivity是非常強大的。其眾多的功能之一是圍繞錯誤處理。 調度子活動的時的基本錯誤處理。 當NativeActivity執行的時候&#xff0c;它是通過一個NativeActivityConte…

程序員提高建議之踏踏實實“扎馬步”

踏踏實實“扎馬步” 今天無意中看了“校長”的“程序員&司機”&#xff0c;其中談到了關于程序員速成的問題。其實速成班畢業的“系統殺手”早已在遍布大江南北&#xff0c;只是在互聯網時代&#xff0c;互聯網的應用型軟件生命周期越來越短&#xff0c;業務驅動主導…

c語言scanf返回值

1. scanf 函數是有返回值的&#xff0c;它的返回值可以分成三種情況1) 正整數&#xff0c;表示正確輸入參數的個數。例如執行 scanf("%d %d", &a, &b);如果用戶輸入"3 4"&#xff0c;可以正確輸入&#xff0c;返回2&#xff08;正確輸入了兩個變量…

gpgga格式讀取MATLAB,GPS編碼格式及讀取.doc

GPS接收機只要處于工作狀態就會源源不斷地把接收并計算出的GPS導航定位信息通過串口傳送到計算機中。前面的代碼只負責從串口接收數據并將其放置于緩存&#xff0c;在沒有進一步處理之前緩存中是一長串字節流&#xff0c;這些信息在沒有經過分類提取之前是無法加以利用的。因此…

Cadence 電源完整性仿真實踐(二)

轉載于:http://blog.csdn.net/wu20093346/article/details/38050917 通過以上步驟對每個平面進行了單節點分析并觀測了響應曲線&#xff0c;接下來將觀測平面對的目標阻抗是否滿足要求&#xff0c;通過選擇電容器的方法來減小含有電容器阻抗響應曲線中的反諧振波峰。在SigWave窗…

Johnson 全源最短路徑算法

解決單源最短路徑問題&#xff08;Single Source Shortest Paths Problem&#xff09;的算法包括&#xff1a; Dijkstra 單源最短路徑算法&#xff1a;時間復雜度為 O(E VlogV)&#xff0c;要求權值非負&#xff1b; Bellman-Ford 單源最短路徑算法&#xff1a;時間復雜度為 O…

單循環鏈表中設置尾指針比設置頭指針更好的原因

尾指針是指向終端結點的指針&#xff0c;用它來表示單循環鏈表可以使得查找鏈表的開始結點和終端結點都很方便。 設一帶頭結點的單循環鏈表&#xff0c;其尾指針為rear&#xff0c;則開始結點和終端結點的位置分別是rear->next->next和rear,查找時間都是O(1)。 若用頭指…

為何大部分人成不了技術專家?

此文為我在CSDN的新的SNS里看到的&#xff0c;感觸很深&#xff0c;和大家分享一下.里面的許多人的觀點都讓我受益匪淺。 如果你是項目經理&#xff0c;產品經理或者架構師&#xff0c;我真誠邀請你加入 如果你還是學生或者還是初學者&#xff0c;我建議你先等等&#xff0c;…

Machine Learning 學習筆記1 - 基本概念以及各分類

What is machine learning? 并沒有廣泛認可的定義來準確定義機器學習。以下定義均為譯文&#xff0c;若以后有時間&#xff0c;將補充原英文...... 定義1、來自Arthur Samuel&#xff08;上世紀50年代、西洋棋程序&#xff09; 在進行特定編程的情況下給予計算機學習能力的領域…

值傳遞與地址傳遞

值傳遞與地址傳遞的區別&#xff1a;兩者其實傳遞的都是一個內存單元的內容。不同的是&#xff0c;值傳遞傳遞的內容是一個變量的值&#xff0c;得到這個值后&#xff0c;對這個值的修改不能改變原變量的值&#xff1b;而地址傳遞傳遞的是一個變量的地址&#xff0c;得到傳遞的…

蒙特 卡羅方法matlab,蒙特·卡羅方法中的數學之美,你一定不想錯過

原標題&#xff1a;蒙特卡羅方法中的數學之美&#xff0c;你一定不想錯過有方教育——我們致力于為中學生提供學界和業界前沿的學術科研教育內容&#xff0c;幫助學生參加海外科研項目&#xff0c;在提升申請競爭力的同時&#xff0c;獲得領跑優勢。一、概述蒙特卡羅方法(Monte…