您好,登錄后才能下訂單哦!
這篇文章主要講解了在C#/.NET Core中責任鏈模式的使用方法,內容清晰明了,對此有興趣的小伙伴可以學習一下,相信大家閱讀完之后會有幫助。
最近我有一個朋友在研究經典的“Gang Of Four”設計模式。他經常來詢問我在實際業務應用中使用了哪些設計模式。單例模式、工廠模式、中介者模式 - 都是我之前使用過,甚至寫過相關文章的模式。但是有一種模式是我還沒有寫過文章,即責任鏈模式。
什么是責任鏈?#
責任鏈模式(之前我經常稱之為命令鏈模式)是一種允許以使用分層方式”處理“對象的模式。在維基百科中的經典定義是
在面向對象設計中,責任鏈模式是一種由命令對象源及其一系列處理對象組成的設計模式。每個處理對象包含了它可以處理的命令對象的邏輯,其余的將傳遞給鏈中的下一個處理對象。當然,這里還存在一種將新的處理對象追加到鏈尾的機制。因此責任鏈是If..else if.. else if...else...endif的面向對象版本。其優點是可以在運行時動態重新排列或配置條件操作塊。
也許你會覺著上面的概念描述過于抽象,不容易理解,那么下面讓我們來看一個真實生活中的例子。
這里假設我們擁有一家銀行,銀行里面有3個級別的員工,分別是“柜員”、“主管”、“銀行經理”。如果有人來取款,“柜員”只允許10,000美元以下的取款操作。如果金額超過10,000美元,那么它的請求將傳遞給“主管”。“主管”可以處理不超過100,000美元的請求,但前提是該賬戶在必須有身份證ID。如果沒有身份證ID,則當前請求必須被拒絕。如果取款金額超過100,000美元,則當前請求可以轉交給“銀行經理”,“銀行經理”可以批準任何取款金額,因為如果有人取超過100,000美元的金額,他們就是VIP, 我們不在乎VIP的身份證ID和其他規定。
這就是我們前面討論的分層“鏈”,每個人都嘗試處理當前請求,如果沒有滿足要求,就傳遞給下一個。如果我們將這種場景轉換成代碼,就是我們所說的責任鏈模式。但是在這之前,讓我們先來看一個糟糕的實現方法。
一個糟糕的實現方式#
下面我們先使用If/Else塊來解決當前問題。
class BankAccount { bool idOnRecord { get; set; } void WithdrawMoney(decimal amount) { // 柜員處理 if(amount < 10000) { Console.WriteLine("柜員提取的金額"); } // 主管處理 else if (amount < 100000) { if(!idOnRecord) { throw new Exception("客戶沒有身份證ID"); } Console.WriteLine("主管提取的金額"); } else { Console.WriteLine("銀行經理提取的金額"); } } }
以上這種實現方式有幾個問題:
使用責任鏈模式編碼#
下面讓我們重寫一些這部分代碼。與之前不同,這里我們創建一些“員工”對象,里面封裝了他們的處理邏輯。這里最重要的是,我們需要給每個員工對象指定一個直屬上級,以便當他們處理不了當前請求的時候,可以將請求傳遞給直屬上級。
interface IBankEmployee { IBankEmployee LineManager { get; } void HandleWithdrawRequest(BankAccount account, decimal amount); } class Teller : IBankEmployee { public IBankEmployee LineManager { get; set; } public void HandleWithdrawRequest(BankAccount account, decimal amount) { if(amount > 10000) { LineManager.HandleWithdrawRequest(account, amount); return; } Console.WriteLine("柜員提取的金額"); } } class Supervisor : IBankEmployee { public IBankEmployee LineManager { get; set; } public void HandleWithdrawRequest(BankAccount account, decimal amount) { if (amount > 100000) { LineManager.HandleWithdrawRequest(account, amount); return; } if(!account.idOnRecord) { throw new Exception("客戶沒有身份證ID"); } Console.WriteLine("主管提取的金額"); } } class BankManager : IBankEmployee { public IBankEmployee LineManager { get; set; } public void HandleWithdrawRequest(BankAccount account, decimal amount) { Console.WriteLine("銀行經理提取的金額"); } }
我們可以通過指定上級的方式創建出責任鏈。這看起來很像一個組織結構圖。
var bankManager = new BankManager(); var bankSupervisor = new Supervisor { LineManager = bankManager }; var frontLineStaff = new Teller { LineManager = bankSupervisor };
這里我們可以創建一個BankAccount類,并將取款方法轉換為由前臺員工處理。
class BankAccount { public bool idOnRecord { get; set; } public void WithdrawMoney(IBankEmployee frontLineStaff, decimal amount) { frontLineStaff.HandleWithdrawRequest(this, amount); } }
現在,當我們進行取款請求的時候,“柜員”總是第一個來處理,如果處理不了,它會自動將請求發給直屬領導。這種模式的優雅之處有以下幾點:
擴展我們的例子#
盡管我認為以上的例子已經能很好的說明這種模式,但是通常你會發現有些人會使用一個方法叫做SetNext.一般來說,我覺著這在C#中是非常罕見的,因為C#中我們可以使用屬性獲取器和設置器。使用SetVariableName方法通常都是C++時代的事情了,那時候這通常是封裝變量的首選方法。
但這里最重要的是,其他示例通常使用抽象類來加強請求傳遞的方式。在前面代碼中有一個問題是,將請求傳遞給下一個處理器的時候,編寫了許多重復代碼。那么就讓我們來整理一下代碼。
這里我們要做的第一件事情就是創建一個抽象類,這個抽象類使我們能夠通過標準化的方式處理提款請求。它應該定義一個檢測條件,如果條件滿足,就執行提款,反之,就將請求傳遞給直屬上級。經過修改之后的代碼如下:
interface IBankEmployee { IBankEmployee LineManager { get; } void HandleWithdrawRequest(BankAccount account, decimal amount); } abstract class BankEmployee : IBankEmployee { public IBankEmployee LineManager { get; private set; } public void SetLineManager(IBankEmployee lineManager) { this.LineManager = lineManager; } public void HandleWithdrawRequest(BankAccount account, decimal amount) { if (CanHandleRequest(account, amount)) { Withdraw(account, amount); } else { LineManager.HandleWithdrawRequest(account, amount); } } abstract protected bool CanHandleRequest(BankAccount account, decimal amount); abstract protected void Withdraw(BankAccount account, decimal amount); }
下一步,我們需要修改所有的員工類,使其繼承自BankEmployee抽象類
class Teller : BankEmployee, IBankEmployee { protected override bool CanHandleRequest(BankAccount account, decimal amount) { if (amount > 10000) { return false; } return true; } protected override void Withdraw(BankAccount account, decimal amount) { Console.WriteLine("柜員提取的金額"); } } class Supervisor : BankEmployee, IBankEmployee { protected override bool CanHandleRequest(BankAccount account, decimal amount) { if (amount > 100000) { return false; } return true; } protected override void Withdraw(BankAccount account, decimal amount) { if (!account.idOnRecord) { throw new Exception("客戶沒有身份證ID"); } Console.WriteLine("主管提取的金額"); } } class BankManager : BankEmployee, IBankEmployee { protected override bool CanHandleRequest(BankAccount account, decimal amount) { return true; } protected override void Withdraw(BankAccount account, decimal amount) { Console.WriteLine("銀行經理提取的金額"); } }
這里請注意,在所有的場景中,都會調用抽象類中的HandleWithdrawRequest公共方法。 該方法會調用子類中定義的CanHandleRequest方法來檢測當前角色是否滿足處理請求的條件,如果滿足,就調用子類中的Withdraw方法處理請求,否則就會嘗試將請求傳遞給上級角色。
我們只需要像以下代碼這樣,更改創建員工鏈的方式即可:
var bankManager = new BankManager(); var bankSupervisor = new Supervisor(); bankSupervisor.SetLineManager(bankManager); var frontLineStaff = new Teller(); frontLineStaff.SetLineManager(bankSupervisor);
這里我需要再次重申,我并不喜歡使用SetXXX這種方法,但是許多例子中都喜歡這么使用,所以我就把它加了進來。
在一些例子中,也會將判斷員工是否滿足處理請求的條件放在抽象類中。我個人不喜歡這樣做,因為這意味著所有的處理程序不得不使用相似的邏輯。例如,目前所有的檢查都是基于提取金額的,但是如果我們想要實現一個特殊的處理程序,它的條件和VIP標志有關,那么我們將不得不又在抽象類中重新使用IF/Else, 這又將我們帶回到了IF/Else地獄中。
什么時候應該使用責任鏈模式?#
這種模式最佳的使用場景是,你的業務上有一個邏輯上的處理鏈,這個處理鏈每次必須按照順序運行。這里請注意,鏈分叉是這種模式的一個變體, 但是很快處理起來就會非常復雜。因此,當我對現實世界中“命令鏈”場景建模的時候,我通常會使用這種模式。這就是我以銀行為例的原因,因為它就是現實世界中可以用代碼建模的“責任鏈”。
看完上述內容,是不是對在C#/.NET Core中責任鏈模式的使用方法有進一步的了解,如果還想學習更多內容,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。