網(wǎng)站首頁 編程語言 正文
.Net行為型設(shè)計模式之職責(zé)鏈模式(Chain?of?Responsibility)_基礎(chǔ)應(yīng)用
作者:springsnow ? 更新時間: 2022-07-24 編程語言一、動機(Motivate)
在軟件構(gòu)建過程中,一個請求可能被多個對象處理,但是每個請求在運行時只能有一個接受者,如果顯示指定,將必不可少地帶來請求發(fā)送者與接受者的緊耦合。如何使請求的發(fā)送者不需要指定具體的接受者,讓請求的接受者自己在運行時決定來處理請求,從而使兩者解耦。
二、意圖(Intent)
避免請求發(fā)送者與接收者耦合在一起,讓多個對象都有可能接受請求,將這些對象連接成一條鏈,并且沿著這條鏈傳遞請求,知道有對象處理它為止。???????????????????????????????? ——《設(shè)計模式》GoF
三、結(jié)構(gòu)圖(Structure)
四、模式的組成
可以看出,在職責(zé)鏈模式的結(jié)構(gòu)圖有以下角色:
(1)、抽象處理者角色(Handler):抽象處理者定義了一個處理請求的接口,它一般設(shè)計為抽象類,由于不同的具體處理者處理請求的方式不同,因此在其中定義了抽象請求處理方法。因為每一個處理者的下家還是一個處理者,因此在抽象處理者中定義了一個自類型的對象,作為其對下家的引用。通過該引用,處理者可以連成一條鏈。
(2)、具體處理者角色(ConcreteHandler):具體處理者是抽象處理者的子類,它可以處理用戶請求,在具體處理者類中實現(xiàn)了抽象處理者中定義的抽象處理方法,在處理請求之前需要進行判斷,看是否有相應(yīng)的處理權(quán)限,如果可以處理請求就處理它,否則將請求轉(zhuǎn)發(fā)給后繼者;在具體處理者中可以訪問鏈中下一個對象,以便請求的轉(zhuǎn)發(fā)。
五、職責(zé)鏈模式的代碼實現(xiàn)
在現(xiàn)實生活中,職責(zé)鏈模式的例子也是很多的,例如:公司的請假流程就是一個很好的職責(zé)鏈模式的例子,如果請假半天,只要告訴本部門經(jīng)理就可以了;如果請假7天或者以上必須人事總監(jiān)批準;如果請假15天以上,那就要經(jīng)過總裁批準了。還有類似的例子就是采購的流程,其流程也是職責(zé)鏈模式很好的體現(xiàn),采購的金額不同,需要批準的人員也不同,比如:部門采購1萬元的紙品,只要部門領(lǐng)導(dǎo)簽批就可以,如果要采購大于1萬小于5萬的物品,那就需要財務(wù)經(jīng)理簽批了,如果采購30萬的原材料或者物品,那就需要總裁或者類似角色才能審批了。接下來我們就以采購的實例來說明職責(zé)鏈模式。實現(xiàn)代碼如下:
static void Main(string[] args)
{
PurchaseRequest requestDao = new PurchaseRequest(8000.0, "單刀5把");
PurchaseRequest requestHuaJi = new PurchaseRequest(10000.0, "10把方天畫戟");
PurchaseRequest requestJian = new PurchaseRequest(80000.0, "5把金絲龍鱗閃電劈");
Approver manager = new Manager("黃飛鴻");
Approver financial = new FinancialManager("黃麒英");
Approver ceo = new CEO("十三姨");
// 設(shè)置職責(zé)鏈
manager.NextApprover = financial;
financial.NextApprover = ceo;
// 處理請求
manager.ProcessRequest(requestDao);
manager.ProcessRequest(requestHuaJi);
manager.ProcessRequest(requestJian);
}
// 采購請求
public sealed class PurchaseRequest
{
// 金額
public double Amount { get; set; }
// 產(chǎn)品名字
public string ProductName { get; set; }
public PurchaseRequest(double amount, string productName)
{
Amount = amount;
ProductName = productName;
}
}
//抽象審批人,Handler---相當于“抽象處理者角色”
public abstract class Approver
{
//下一位審批人,由此形成一條鏈
public Approver NextApprover { get; set; }
//審批人的名稱
public string Name { get; set; }
public Approver(string name)
{
this.Name = name;
}
//處理請求
public abstract void ProcessRequest(PurchaseRequest request);
}
//部門經(jīng)理----相當于“具體處理者角色” ConcreteHandler
public sealed class Manager : Approver
{
public Manager(string name) : base(name) { }
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount <= 10000.0)
{
Console.WriteLine("{0} 部門經(jīng)理批準了對原材料{1}的采購計劃!", this.Name, request.ProductName);
}
else if (NextApprover != null)
{
NextApprover.ProcessRequest(request);
}
}
}
//財務(wù)經(jīng)理---相當于“具體處理者角色”ConcreteHandler
public sealed class FinancialManager : Approver
{
public FinancialManager(string name) : base(name) { }
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount > 10000.0 && request.Amount <= 50000.0)
{
Console.WriteLine("{0} 財務(wù)經(jīng)理批準了對原材料{1}的采購計劃!", this.Name, request.ProductName);
}
else if (NextApprover != null)
{
NextApprover.ProcessRequest(request);
}
}
}
//總裁---相當于“具體處理者角色” ConcreteHandler
public sealed class CEO : Approver
{
public CEO(string name) : base(name) { }
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount > 50000.0 && request.Amount < 300000.0)
{
Console.WriteLine("{0} 總裁批準了對原材料 {1} 的采購計劃!", this.Name, request.ProductName);
}
else
{
Console.WriteLine("這個采購計劃的金額比較大,需要一次董事會會議討論才能決定!");
}
}
}
六、職責(zé)鏈模式的實現(xiàn)要點:
Chain of Responsibility模式的應(yīng)用場合在于“一個請求可能有多個接受者,但是最后真正的接受者只有一個”,只有這時候請求發(fā)送者與接受者的耦合才有可能出現(xiàn)“變化脆弱”的癥狀,職責(zé)鏈的目的就是將二者解耦,從而更好地應(yīng)對變化。
應(yīng)用了Chain of Responsibility模式后,對象的職責(zé)分派將更具靈活性。我們可以在運行時動態(tài)添加/修改請求的處理職責(zé)。
當我們要新增一個DHandler處理請求,就不需再改原來的代碼了,遵從了開放封閉原則。這樣我們的程序就更賦予變化,更有變化的抵抗力。Handler類本身繼承自BaseHandler類型,又包含了一個BaseHandler類型的對象,這點類似Decorator模式。
如果請求傳遞到職責(zé)鏈的末尾仍得不到處理,應(yīng)該有一個合理的缺省機制。這也是每一個接受對象的責(zé)任,而不是發(fā)出請求的對象的責(zé)任。
1、職責(zé)鏈模式的主要優(yōu)點有:
1】、降低耦合度:職責(zé)鏈模式使得一個對象無需知道是其他哪一個對象處理其請求。對象僅需知道該請求會被處理即可,接受者和發(fā)送者都沒有對方的明確信息,且鏈中的對象不需要知道鏈的結(jié)構(gòu),有客戶端負責(zé)鏈的創(chuàng)建。
2】、可簡化對象的相互連接:接受者對象僅需維持一個指向其后繼者的引用,而不需維持它對所有的候選處理者的引用。
3】、增強給對象指派職責(zé)的靈活性:在給對象分派職責(zé)時,職責(zé)鏈可以給我們帶來更多的靈活性。可以通過在運行時對該連進行動態(tài)的增加或修改處理一個請求的職責(zé)。
4】、增加新的請求處理類很方便:在系統(tǒng)中增加一個新的請求處理者無需修改原有系統(tǒng)的代碼,只需要在客戶端重新建鏈即可,從這一點看來是符合“開閉原則”的。
2、職責(zé)鏈模式的主要缺點有:
1】、在找到正確的處理對象之前,所有的條件判定都要執(zhí)行一遍,當責(zé)任鏈過長時,可能會引起性能的問題。
2】、可能導(dǎo)致某個請求不被處理。
3】、客戶端需要組裝這個鏈條,耦合了客戶端和鏈條的組成結(jié)構(gòu),可以把這個在客戶端的組合動作提到外面,通過配置來做,會更好點。
3、在下面的情況下可以考慮使用職責(zé)鏈模式:
1】、一個系統(tǒng)的審批需要多個對象才能完成處理的情況下,例如請假系統(tǒng)等。
2】、代碼中存在多個if-else語句的情況下,此時可以考慮使用責(zé)任鏈模式來對代碼進行重構(gòu)
3】、有多個對象可以處理同一個請求,具體哪個對象處理該請求有運行時刻自動確定。客戶端只需將請求提交到鏈上,無須關(guān)心請求的處理對象是誰以及它是如何處理的。
4】、不明確指定接受者的情況下,向多個對象中的一個提交一個請求。請求的發(fā)送者與請求者解耦,請求將沿著鏈進行傳遞,尋求響應(yīng)的處理者。
5】、可動態(tài)指定一組對象處理請求。客戶端可以動態(tài)創(chuàng)建職責(zé)鏈來處理請求,還可以動態(tài)改變鏈中處理者之間的先后次序
七、.NET 職責(zé)鏈模式的實現(xiàn)
這個模式在Net框架中的實現(xiàn)不多,我感覺這個模式的使用場景更多的是在業(yè)務(wù)系統(tǒng)總才會有更大的用處。這種模式在處理UI的消息時很常用,但實際上Windows消息循環(huán)還是硬編碼的結(jié)構(gòu)。因為效率上的考慮,Windows消息循環(huán)是哪個對象有一個請求,則直接到達處理函數(shù)的地址。如果鏈條上的對象多了,而真正處理的函數(shù)在鏈條后部分,效率會很低下。因此我們在使用這種模式的時候更適合業(yè)務(wù)流程,即對性能要求不是特別高的情況更加常用。
原文鏈接:https://www.cnblogs.com/springsnow/p/11359376.html
相關(guān)推薦
- 2022-12-12 Android?DataBinding類關(guān)系深入探究_Android
- 2022-07-11 Python利用xlrd?與?xlwt?模塊操作?Excel_python
- 2022-06-18 Elasticsearches之python使用及Django與Flask集成示例_python
- 2023-05-17 一文速學(xué)Python+Pyecharts繪制樹形圖_python
- 2023-03-01 Shell腳本read用法實現(xiàn)_linux shell
- 2022-05-03 C++STL函數(shù)和排序算法的快排以及歸并排序詳解_C 語言
- 2021-12-05 C++11?關(guān)鍵字?const?使用小結(jié)_C 語言
- 2022-09-13 fastlane自動化打包iOS?APP過程示例_IOS
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支