欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解如何在C#/.NET Core中使用責(zé)任鏈模式

 更新時間:2020年05月25日 11:17:23   作者:Lamond Lu  
這篇文章主要介紹了詳解如何在C#/.NET Core中使用責(zé)任鏈模式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

最近我有一個朋友在研究經(jīng)典的“Gang Of Four”設(shè)計模式。他經(jīng)常來詢問我在實(shí)際業(yè)務(wù)應(yīng)用中使用了哪些設(shè)計模式。單例模式、工廠模式、中介者模式 - 都是我之前使用過,甚至寫過相關(guān)文章的模式。但是有一種模式是我還沒有寫過文章,即責(zé)任鏈模式。

什么是責(zé)任鏈?#

責(zé)任鏈模式(之前我經(jīng)常稱之為命令鏈模式)是一種允許以使用分層方式”處理“對象的模式。在維基百科中的經(jīng)典定義是

在面向?qū)ο笤O(shè)計中,責(zé)任鏈模式是一種由命令對象源及其一系列處理對象組成的設(shè)計模式。每個處理對象包含了它可以處理的命令對象的邏輯,其余的將傳遞給鏈中的下一個處理對象。當(dāng)然,這里還存在一種將新的處理對象追加到鏈尾的機(jī)制。因此責(zé)任鏈?zhǔn)荌f..else if.. else if...else...endif的面向?qū)ο蟀姹?。其?yōu)點(diǎn)是可以在運(yùn)行時動態(tài)重新排列或配置條件操作塊。

也許你會覺著上面的概念描述過于抽象,不容易理解,那么下面讓我們來看一個真實(shí)生活中的例子。

這里假設(shè)我們擁有一家銀行,銀行里面有3個級別的員工,分別是“柜員”、“主管”、“銀行經(jīng)理”。如果有人來取款,“柜員”只允許10,000美元以下的取款操作。如果金額超過10,000美元,那么它的請求將傳遞給“主管”?!爸鞴堋笨梢蕴幚聿怀^100,000美元的請求,但前提是該賬戶在必須有身份證ID。如果沒有身份證ID,則當(dāng)前請求必須被拒絕。如果取款金額超過100,000美元,則當(dāng)前請求可以轉(zhuǎn)交給“銀行經(jīng)理”,“銀行經(jīng)理”可以批準(zhǔn)任何取款金額,因?yàn)槿绻腥巳〕^100,000美元的金額,他們就是VIP, 我們不在乎VIP的身份證ID和其他規(guī)定。

這就是我們前面討論的分層“鏈”,每個人都嘗試處理當(dāng)前請求,如果沒有滿足要求,就傳遞給下一個。如果我們將這種場景轉(zhuǎn)換成代碼,就是我們所說的責(zé)任鏈模式。但是在這之前,讓我們先來看一個糟糕的實(shí)現(xiàn)方法。

一個糟糕的實(shí)現(xiàn)方式#

下面我們先使用If/Else塊來解決當(dāng)前問題。

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("銀行經(jīng)理提取的金額");
    }
  }
}

以上這種實(shí)現(xiàn)方式有幾個問題:

  • 添加一種新的員工級別會相當(dāng)困難,因?yàn)镮F/Else代碼塊看起來太亂了
  • “主管”檢查身份證ID的邏輯在某種程度上很難進(jìn)行單元測試,因?yàn)樗仨毷紫韧ㄟ^其他的檢查
  • 雖然現(xiàn)在我們只定義了提款金額的邏輯,但是如果在將來我們想要添加其他檢查(例如:VIP客戶始終由主管來處理), 這種邏輯將很難管理,并且很容易失控。

使用責(zé)任鏈模式編碼#

下面讓我們重寫一些這部分代碼。與之前不同,這里我們創(chuàng)建一些“員工”對象,里面封裝了他們的處理邏輯。這里最重要的是,我們需要給每個員工對象指定一個直屬上級,以便當(dāng)他們處理不了當(dāng)前請求的時候,可以將請求傳遞給直屬上級。

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("銀行經(jīng)理提取的金額");
  }
}

我們可以通過指定上級的方式創(chuàng)建出責(zé)任鏈。這看起來很像一個組織結(jié)構(gòu)圖。

var bankManager = new BankManager();
var bankSupervisor = new Supervisor { LineManager = bankManager };
var frontLineStaff = new Teller { LineManager = bankSupervisor };

這里我們可以創(chuàng)建一個BankAccount類,并將取款方法轉(zhuǎn)換為由前臺員工處理。

class BankAccount
{
  public bool idOnRecord { get; set; }

  public void WithdrawMoney(IBankEmployee frontLineStaff, decimal amount)
  {
     frontLineStaff.HandleWithdrawRequest(this, amount);
  }
}

現(xiàn)在,當(dāng)我們進(jìn)行取款請求的時候,“柜員”總是第一個來處理,如果處理不了,它會自動將請求發(fā)給直屬領(lǐng)導(dǎo)。這種模式的優(yōu)雅之處有以下幾點(diǎn):

  1. 鏈中的后續(xù)子項(xiàng)并不需要知道是哪個子項(xiàng)將命令傳遞給它的。就像這里,“主管”不需要知道是為什么下級“柜員”為什么會把請求傳遞給他
  2. "柜員"不需要知道整個鏈。他僅負(fù)責(zé)將請求傳遞給上級""主管"",期望請求能在上級“主管”那里被處理(當(dāng)前也許還需要進(jìn)一步的傳遞處理)即可
  3. 當(dāng)引入新員工類型的時候,整個組織架構(gòu)圖很容易變更。例如, 我創(chuàng)建了一個新的“柜員經(jīng)理”角色,他能處理10,000-50,000美元之間的提款請求,“柜員經(jīng)理”的直屬上級是“主管”。這里我們并不需要對“主管”對象做任何的處理,只需要將“柜員”的直屬上級改為“柜員經(jīng)理”即可
  4. 當(dāng)編寫單元測試的時候,我們可以一次只關(guān)注一個雇員角色了。例如,在測試“主管”邏輯的時候,我們就不需要測試“柜員”的邏輯了

擴(kuò)展我們的例子#

盡管我認(rèn)為以上的例子已經(jīng)能很好的說明這種模式,但是通常你會發(fā)現(xiàn)有些人會使用一個方法叫做SetNext.一般來說,我覺著這在C#中是非常罕見的,因?yàn)镃#中我們可以使用屬性獲取器和設(shè)置器。使用SetVariableName方法通常都是C++時代的事情了,那時候這通常是封裝變量的首選方法。

但這里最重要的是,其他示例通常使用抽象類來加強(qiáng)請求傳遞的方式。在前面代碼中有一個問題是,將請求傳遞給下一個處理器的時候,編寫了許多重復(fù)代碼。那么就讓我們來整理一下代碼。

這里我們要做的第一件事情就是創(chuàng)建一個抽象類,這個抽象類使我們能夠通過標(biāo)準(zhǔn)化的方式處理提款請求。它應(yīng)該定義一個檢測條件,如果條件滿足,就執(zhí)行提款,反之,就將請求傳遞給直屬上級。經(jīng)過修改之后的代碼如下:

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("銀行經(jīng)理提取的金額");
  }
}

這里請注意,在所有的場景中,都會調(diào)用抽象類中的HandleWithdrawRequest公共方法。 該方法會調(diào)用子類中定義的CanHandleRequest方法來檢測當(dāng)前角色是否滿足處理請求的條件,如果滿足,就調(diào)用子類中的Withdraw方法處理請求,否則就會嘗試將請求傳遞給上級角色。

我們只需要像以下代碼這樣,更改創(chuàng)建員工鏈的方式即可:

var bankManager = new BankManager();

var bankSupervisor = new Supervisor();
bankSupervisor.SetLineManager(bankManager);

var frontLineStaff = new Teller();
frontLineStaff.SetLineManager(bankSupervisor);

這里我需要再次重申,我并不喜歡使用SetXXX這種方法,但是許多例子中都喜歡這么使用,所以我就把它加了進(jìn)來。

在一些例子中,也會將判斷員工是否滿足處理請求的條件放在抽象類中。我個人不喜歡這樣做,因?yàn)檫@意味著所有的處理程序不得不使用相似的邏輯。例如,目前所有的檢查都是基于提取金額的,但是如果我們想要實(shí)現(xiàn)一個特殊的處理程序,它的條件和VIP標(biāo)志有關(guān),那么我們將不得不又在抽象類中重新使用IF/Else, 這又將我們帶回到了IF/Else地獄中。

什么時候應(yīng)該使用責(zé)任鏈模式?#

這種模式最佳的使用場景是,你的業(yè)務(wù)上有一個邏輯上的處理鏈,這個處理鏈每次必須按照順序運(yùn)行。這里請注意,鏈分叉是這種模式的一個變體, 但是很快處理起來就會非常復(fù)雜。因此,當(dāng)我對現(xiàn)實(shí)世界中“命令鏈”場景建模的時候,我通常會使用這種模式。這就是我以銀行為例的原因,因?yàn)樗褪乾F(xiàn)實(shí)世界中可以用代碼建模的“責(zé)任鏈”。

到此這篇關(guān)于詳解如何在C#/.NET Core中使用責(zé)任鏈模式的文章就介紹到這了,更多相關(guān)C#/.NET Core 責(zé)任鏈模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

原文:Chain Of Responsbility Pattern In C#/.NET Core
作者:Wade
譯者:Lamond Lu
出處:https://www.cnblogs.com/lwqlun/p/12846451.html

版權(quán):本文采用「署名 4.0 國際」知識共享許可協(xié)議進(jìn)行許可。

相關(guān)文章

  • C#中int[][]與int[,]的使用與區(qū)別

    C#中int[][]與int[,]的使用與區(qū)別

    本文主要介紹了C#中int[][]與int[,]的使用與區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C#異步調(diào)用的好處和方法分享

    C#異步調(diào)用的好處和方法分享

    我們要明確,為什么要進(jìn)行異步回調(diào)?眾所周知,普通方法運(yùn)行,是單線程的,如果中途有大型操作(如:讀取大文件,大批量操作數(shù)據(jù)庫,網(wǎng)絡(luò)傳輸?shù)龋?,都會?dǎo)致方法阻塞,表現(xiàn)在界面上就是,程序卡或者死掉,界面元素不動了,不響應(yīng)了
    2012-04-04
  • C#實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)出到word或者Excel中的方法

    C#實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)出到word或者Excel中的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)出到word或者Excel中的方法,涉及C#操作word及Excel格式文件的方法,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-08-08
  • C# 靈活使用類的方法

    C# 靈活使用類的方法

    本文主要介紹了C# 靈活使用類的方法,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • C#實(shí)現(xiàn)獲取計算機(jī)信息的示例代碼

    C#實(shí)現(xiàn)獲取計算機(jī)信息的示例代碼

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)獲取計算機(jī)軟硬件信息的相關(guān)知識,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,有需要的小伙伴可以參考下
    2024-01-01
  • 利用C#實(shí)現(xiàn)將小數(shù)值四舍五入為整數(shù)

    利用C#實(shí)現(xiàn)將小數(shù)值四舍五入為整數(shù)

    在項(xiàng)目的開發(fā)中,遇到一些除法計算內(nèi)容會產(chǎn)生小數(shù)值,但是又需要根據(jù)項(xiàng)目的實(shí)際情況將這些小數(shù)內(nèi)容化為整數(shù),所以本文為大家整理了C#實(shí)現(xiàn)將小數(shù)值四舍五入為整數(shù)的方法,希望對大家有所幫助
    2023-07-07
  • WPF自定義TreeView控件樣式實(shí)現(xiàn)QQ聯(lián)系人列表效果

    WPF自定義TreeView控件樣式實(shí)現(xiàn)QQ聯(lián)系人列表效果

    TreeView控件在項(xiàng)目中使用比較頻繁,下面這篇文章主要給大家介紹了關(guān)于WPF自定義TreeView控件樣式實(shí)現(xiàn)QQ聯(lián)系人列表效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。
    2018-04-04
  • c#中多線程訪問winform控件的若干問題小結(jié)

    c#中多線程訪問winform控件的若干問題小結(jié)

    大部分情況下都會碰到使用多線程控制界面上控件信息的問題。然而我們并不能用傳統(tǒng)方法來解決這個問題,下面我將詳細(xì)的介紹
    2013-10-10
  • C#遍歷文件夾及其子目錄的完整實(shí)現(xiàn)方法

    C#遍歷文件夾及其子目錄的完整實(shí)現(xiàn)方法

    這篇文章主要介紹了C#遍歷文件夾及其子目錄的方法,涉及C#文件與目錄的基本操作技巧,簡單實(shí)用,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • C#中DateTime.Compare()比較時間大小

    C#中DateTime.Compare()比較時間大小

    本文主要介紹了C#中DateTime.Compare()比較時間大小,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04

最新評論