趣谈设计模式 | 职责链模式(ChainOfResposibility):请求的转发处理
文章目錄
- 案例:企業(yè)信息處理
- 職責(zé)鏈模式
- 總結(jié)
- 完整代碼與文檔
案例:企業(yè)信息處理
對(duì)于一個(gè)企業(yè)來說,每天難免的要收到大量的信息,有求職者發(fā)送過來的簡歷、其他公司的商務(wù)合作信息、又或者是和一些企業(yè)或客戶的法律糾紛信息、又或者是一些廣告、推銷信息。面對(duì)這大量的信息,處理起來十分的麻煩。
于是企業(yè)準(zhǔn)備開發(fā)一套信息管理系統(tǒng),初步的設(shè)計(jì)如下
我們設(shè)計(jì)了一個(gè)信息的管理員,他會(huì)判斷信息的種類,并將信息轉(zhuǎn)發(fā)到對(duì)應(yīng)的部門中,讓這些部門來處理它們對(duì)應(yīng)的任務(wù)。
但是,這樣的設(shè)計(jì)存在著嚴(yán)重的問題。
隨著我們公司的規(guī)模不斷擴(kuò)張,各個(gè)部門的職責(zé)也更加細(xì)化,對(duì)于這些信息,我們又新增了幾個(gè)新部門進(jìn)行處理,同時(shí)我們可能又會(huì)對(duì)業(yè)務(wù)細(xì)化,將一個(gè)部門拆分成多個(gè)部門。甚至我們又會(huì)對(duì)信息進(jìn)行分級(jí),例如普通信息管理者,機(jī)密信息管理者等等
在這種情況下,管理者存在著大量的職責(zé),違反了單一職責(zé)原則。同時(shí),我們每一次增加、修改部門時(shí),都需要去修改管理者的內(nèi)部實(shí)現(xiàn),這同時(shí)又違反了開放-封閉原則,這樣的代碼不僅維護(hù)性差,類與類之間也存在著強(qiáng)耦合的關(guān)系,是個(gè)不好的設(shè)計(jì)方案。
為了解決這個(gè)問題,就引入了職責(zé)鏈模式
職責(zé)鏈模式
職責(zé)鏈模式使得多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,知道有一個(gè)對(duì)象處理它為止
職責(zé)鏈模式由兩部分組成
- Handler(處理者接口):提供了處理請(qǐng)求的接口,所有的具體處理者都會(huì)實(shí)現(xiàn)它
- ConcreteHandle(具體處理者):具體處理者,處理它所負(fù)責(zé)的請(qǐng)求,可訪問它的后繼者,如果可以處理則處理,處理不了則將任務(wù)轉(zhuǎn)發(fā)給它的后繼者
類圖如下
根據(jù)職責(zé)鏈模式,此時(shí)我們的關(guān)系是這樣的,我們讓部門之間以鏈表的形式連接起來。
當(dāng)客戶向我們發(fā)送信息后,每個(gè)部門都會(huì)處理自己分內(nèi)的信息,如果處理不了,則將其轉(zhuǎn)發(fā)給職責(zé)鏈中的下一個(gè)部門,讓其繼續(xù)處理。
例如客戶發(fā)送來一個(gè)XXX的求職簡歷,此時(shí)的處理流程是這樣的
下面就以代碼的形式實(shí)現(xiàn)一下這個(gè)功能
首先實(shí)現(xiàn)一個(gè)請(qǐng)求的結(jié)構(gòu),以及處理者的抽象類,其中為了實(shí)現(xiàn)鏈?zhǔn)浇Y(jié)構(gòu),處理者中保留了一個(gè)指向職責(zé)鏈下一個(gè)處理者的指針
//請(qǐng)求結(jié)構(gòu)體,包含請(qǐng)求類型和正文 struct Request {std::string _type;std::string _text; };//處理者抽象類,所有的具體處理者都會(huì)繼承并實(shí)現(xiàn)該類 class Handler { public:Handler(): _sussessor(nullptr){}virtual ~Handler() = default;void setSussessor(Handler* sussessor){_sussessor = sussessor;}virtual void HandlerRequest(const Request& req) = 0;protected:Handler* _sussessor; //繼任者 };接著實(shí)現(xiàn)具體的處理者
#include"Handler.hpp" #include<iostream>//法務(wù)部門 class LegalHandler : public Handler { public:void HandlerRequest(const Request& req) override{if(req._type == "法務(wù)信息"){std::cout << "法務(wù)部門處理法務(wù)信息: " << req._text << std::endl;}else{if(_sussessor != nullptr){_sussessor->HandlerRequest(req);} }} };//商務(wù)部門 class BusinessHandler : public Handler { public:void HandlerRequest(const Request& req) override{if(req._type == "商務(wù)信息"){std::cout << "商務(wù)部門處理商務(wù)信息: " << req._text << std::endl;}else{if(_sussessor != nullptr){_sussessor->HandlerRequest(req);} }} };//人事部門 class PersonnelHandler : public Handler { public:void HandlerRequest(const Request& req) override{if(req._type == "人事信息"){std::cout << "人事部門處理人事信息: " << req._text << std::endl;}else{if(_sussessor != nullptr){_sussessor->HandlerRequest(req);} }} };//雜務(wù)部門,也相當(dāng)于是收尾人,負(fù)責(zé)處理剩余的請(qǐng)求 class MiscellaneousHandler : public Handler { public:void HandlerRequest(const Request& req) override{std::cout << "雜務(wù)部門處理剩余信息: " << req._text << std::endl;} };測試代碼
int main() {Handler* legal = new LegalHandler;Handler* business = new BusinessHandler;Handler* personnel = new PersonnelHandler;Handler* miscellaneous = new MiscellaneousHandler;legal->setSussessor(business);business->setSussessor(personnel);personnel->setSussessor(miscellaneous);legal->HandlerRequest({"法務(wù)信息", "XXX法院傳票"});legal->HandlerRequest({"商務(wù)信息", "XXX商業(yè)合作"});legal->HandlerRequest({"人事信息", "XXX投遞簡歷"});legal->HandlerRequest({"雜務(wù)信息", "XXX無關(guān)信息"});delete legal, business, personnel, miscellaneous; }在當(dāng)前的設(shè)計(jì)中,客戶只需要將所有的信息發(fā)送給職責(zé)鏈的首部即可,如果他能夠處理則直接完成請(qǐng)求,如果無法完成就會(huì)將請(qǐng)求轉(zhuǎn)發(fā)給職責(zé)鏈的下一個(gè)處理者繼續(xù)執(zhí)行
總結(jié)
要點(diǎn)
- 職責(zé)鏈模式將請(qǐng)求的發(fā)送者和接收者解耦
- 可以簡化對(duì)象的相互連接,因?yàn)樗恍枰梨湹慕Y(jié)構(gòu)
- 通過改變鏈內(nèi)的成員或者調(diào)動(dòng)他們的次序,允許我們動(dòng)態(tài)地增加或者修改處理一個(gè)請(qǐng)求的結(jié)構(gòu),增強(qiáng)了給對(duì)象指派職責(zé)的靈活性
- 并不保證請(qǐng)求一定會(huì)被執(zhí)行,如果沒有任何對(duì)象處理它,可能回落到鏈尾端之外,因此最好需要設(shè)立一個(gè)收尾者,來解決所有未被處理的請(qǐng)求
- 由于處理是鏈?zhǔn)絺鬟f的,因此不容易觀察運(yùn)行時(shí)的特征,有礙于除錯(cuò)
應(yīng)用場景
- 有多個(gè)對(duì)象可以處理同一個(gè)請(qǐng)求,具體哪個(gè)對(duì)象處理該請(qǐng)求由運(yùn)行時(shí)刻自動(dòng)確定
- 在不明確指定接收者的情況下,向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求
- 可動(dòng)態(tài)指定一組對(duì)象處理請(qǐng)求
- 通常用于實(shí)現(xiàn)攔截器、過濾器、窗口事件處理等
完整代碼與文檔
如果有需要完整代碼或者markdown文檔的同學(xué)可以點(diǎn)擊下面的github鏈接
github
總結(jié)
以上是生活随笔為你收集整理的趣谈设计模式 | 职责链模式(ChainOfResposibility):请求的转发处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 内存管理 | 物理内存管理:
- 下一篇: 趣谈设计模式 | 桥接模式(Bridge