設計模式之職責鏈模式(Chain Of Responsibility)


一、初識職責鏈模式

一個人在公司工作時間久了,難免遇到一點自己的私事,有私事就可能耽誤上班的時間,可能就要請假,那么和誰去請假呢?可能是每個公司都有自己的請假制度。我們不妨假設:請假半天只要和部門主管說一聲就行了,請假在半天到2天之間要通過人事部門,而請假超過兩天就不那么好申請了,這時可能要總經理或者更高級別的人同意才行了。如果不考慮設計模式直接寫代碼,要完成這個邏輯就可能用到if—else或者多個if了:

View Code
 1 class Manager
 2 {
 3 private:
 4     string name;
 5     string level;
 6 public:
 7     //處理請假
 8     void deal_holiday(int day)
 9     {
10         if(day <= 0.5 && level == "主管")
11         {
12             cout<<level<<" 同意請假 !!"<<endl;
13             return;
14         }
15         if(day > 0.5 && day <= 2 && level == "人事部門")
16         {
17             cout<<level<<" 同意請假 "<<endl;
18             return;
19         }
20         if(day > 2 && level == "總經理")
21         {
22             cout<<level<<" 同意請假 "<<endl;
23             return;
24         }
25         cout<<"各個部門均不同意請假!!!"<<endl;
26     }
27 };

看到這個代碼,就知道了存在許多的問題,比如現在要擴展怎么辦呢??比如又有了董事長,可以處理一個月的請假,這時就要修改這么Manager類中的deal_holiday方法了,顯然不符合單一職責原則(SRP)和開放-封閉原則(OCP),這種類自然也是不合理的類了。現在可以說一說職責鏈模式了,實際上這種情形是適合職責鏈模式的:現在有一個請假信息需要處理,首先是主管處理;主管處理不了,交給人事部門處理;人事部門處理不了,交給總經理處理(如果總經理是最后可能處理請假信息的管理者,那么總經理一定會給出一個答復)。這就構成了一個職責鏈:

如果我們把每個管理者都寫一個類,每個管理者都負責處理請假信息,但是只有當主管處理不了時,才交給人事部門處理,以此類推。那么就是可以寫出來一個職責鏈模式的代碼:

View Code
  1 #include <iostream>
  2 #include <string>
  3 
  4 using namespace std;
  5 
  6 //管理者類
  7 class Manager
  8 {
  9 private:
 10     string name;
 11     Manager *nextManager;
 12 public:
 13     Manager(string n,Manager *m = NULL) : name(n),nextManager(m){};
 14     void set_name(string name)
 15     {
 16         this->name = name;
 17     }
 18     string get_name()
 19     {
 20         return this->name;
 21     }
 22     //設置下一個要處理請假信息的管理者
 23     void set_next_manager(Manager *m)
 24     {
 25         this->nextManager = m;
 26     }
 27     Manager* get_next_manager()
 28     {
 29         return nextManager;
 30     }
 31     //處理請假
 32     virtual void deal_holiday(int day){};
 33 };
 34 //主管類
 35 class ZhuGuan : public Manager
 36 {
 37 public:
 38     ZhuGuan(string n,Manager *m = NULL):Manager(n,m){};
 39     virtual void deal_holiday(int day)
 40     {
 41         if(day <= 0.5)
 42         {
 43             cout<<"主管:"<<get_name()<<"同意請假!!"<<endl;
 44         }
 45         else if(get_next_manager() != NULL)
 46         {
 47             get_next_manager()->deal_holiday(day);
 48         }
 49     }
 50 };
 51 //人事部門類
 52 class RenShi : public Manager
 53 {
 54 public:
 55     RenShi(string n,Manager *m = NULL):Manager(n,m){};
 56     virtual void deal_holiday(int day)
 57     {
 58         if(day < 2)
 59         {
 60             cout<<"人事部:"<<get_name()<<"同意請假!!"<<endl;
 61         }
 62         else if(get_next_manager() != NULL)
 63         {
 64             get_next_manager()->deal_holiday(day);
 65         }
 66     }
 67 };
 68 class ZongJingLi : public Manager
 69 {
 70 public:
 71     ZongJingLi(string n,Manager *m = NULL):Manager(n,m){};
 72     virtual void deal_holiday(int day)
 73     {
 74         if(day < 30)
 75         {
 76             cout<<"總經理:"<<get_name()<<"同意請假!!"<<endl;
 77         }
 78         //總經理室最后一個進行處理的,所以一定要給出一個答復
 79         else
 80         {
 81             cout<<"總經理:"<<get_name()<<"關於你說的請假的事情,由於時間太長,以后再說吧!!"<<endl;
 82         }
 83     }
 84 };
 85 int main()
 86 {
 87     //主管Mike
 88     ZhuGuan Z_G("Mike");
 89     //人事部Tom
 90     RenShi R_S("Tom");
 91     //總經理Vincent
 92     ZongJingLi Z_J_L("Vincent");
 93 
 94     Z_G.set_next_manager(&R_S);
 95     R_S.set_next_manager(&Z_J_L);
 96 
 97     Z_G.deal_holiday(0.5);
 98     Z_G.deal_holiday(1);
 99     Z_G.deal_holiday(3);
100     Z_G.deal_holiday(31);
101     return 0;
102 }

看上面的代碼,我們不難發現,要完成系統的擴展時很方便,只需要在增加管理者類,並且這個"職責鏈”是在客戶端動態確定的哦。當然了如果您現在已經是部門經理了,那么可能您可以直接向總經理請假,這也是可以的。

 

二、再看職責鏈模式

首先看看GoF怎么說:

職責鏈模式(Chain Of Responsibility):使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系。將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理他為止。

說的通俗一點就是:職責鏈模式就是把讓請求沿着鏈條一直傳下去,知道有一個對象能夠處理這個請求。在職責鏈上的對象都有機會處理到請求,但是只有前一個職責鏈不能完成請求的處理,才將請求傳遞給下一個對象。可以看出職責鏈上的對象到底誰能完成請求的處理是不確定的。並且需要注意的是,職責鏈是在客戶端動態確定的哦,具體職責鏈上對象的順序也是動態確定的。還是看看結構圖:

三、職責鏈模式和狀態模式

我的初中生活大概是這樣的:上午七點起床,八點之前洗臉刷牙吃早飯,然后去上課到十一點四十,中午吃飯,然后午睡,下午一點半繼續上課,五點十分下課,然后吃晚飯,從六點二十到九點是晚自習時間,九點之后放學回家,洗洗睡了。

初中的時候請假是這樣的流程:首先是可以找班長請假,班長批准請半天,超過半天班長向老師申請,如果請假時間超過一周,老師要跟副年級主任請示,如果請假超出一個月,主任要跟年級正主任請示,然后被批准,或不被批准。

實際上第一種情況就是適合狀態模式的,而第二種情況適合職責鏈模式。為什么呢??狀態模式中每個對象之間的變換是在程序編譯的時候確定的,也就是編譯的時候每個對象就已經知道自己的下一個狀態了,這適合每個狀態的后繼狀態基本是比較穩定不會發生變化的情況,比如,初中生活就是那樣,每天都是,而職責鏈模式呢?鏈上的每個對象是在客戶端動態確定的,可能每次都不一樣,為什么請假就適合職責鏈模式呢??就是因為職責是動態確定的,如果某天班主任家里有點事,沒來,按照職責鏈模式可以把班長的在職責鏈上的下一對象設置為副年級主任。這樣其他學生還可以正常請假。而如果按照狀態模式的話,如果一旦班主任沒來,學生就不能請超過半天的假啦。。。這不太好吧~~~個人感覺狀態模式和職責鏈模式的區別就是這樣的。

 

四、使用職責鏈模式的場合和優缺點

使用職責鏈模式的場合:

個人覺得,職責鏈模式主要用於當一個請求有多種處理方式的時候,並且具體處理方式不確定的情況。

使用職責鏈模式的優點:

1.增強了系統的可擴展性。

2.使用職責鏈模式可以避免眾多的if或者if-else語句。

3.使用職責鏈模式可以減小對象之間的耦合性。使得對象之間的聯系減小。

4.可以根據需要自由組合工作流程。如工作流程發生變化,可以通過重新分配對象鏈便可適應新的工作流程。

5.責任的分擔。每個類只需要處理自己該處理的工作(不該處理的傳遞給下一個對象完成),明確各類的責任范圍,符合類的最小封裝原則。

使用職責鏈模式的缺點:

1.使用職責鏈模式的時候會有多個處理者對象,但是實際使用的處理者對象卻只有一個,這在某種程度講是資源的浪費。

2.同時職責鏈的建立的合理性要靠客戶端來保證,增加了程序的復雜性,也有可能由於職責鏈導致出錯。

 

 


 

學習中的一點總結,歡迎拍磚哦^^


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM