最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

實(shí)例講解C#中的職責(zé)鏈模式

 更新時(shí)間:2020年07月09日 08:35:11   作者:老胡寫(xiě)代碼  
這篇文章主要介紹了C#中的職責(zé)鏈模式的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

大家好,歡迎來(lái)到老胡的博客,今天我們繼續(xù)了解設(shè)計(jì)模式中的職責(zé)鏈模式,這是一個(gè)比較簡(jiǎn)單的模式。跟往常一樣,我們還是從一個(gè)真實(shí)世界的例子入手,這樣大家也對(duì)這個(gè)模式的應(yīng)用場(chǎng)景有更深刻的理解。

一個(gè)真實(shí)的栗子

作為上班族,相信大家對(duì)請(qǐng)假都不陌生,每個(gè)公司都有自己請(qǐng)假的流程,稍微講究點(diǎn)的公司還會(huì)有細(xì)致的規(guī)定,比如,3天以內(nèi)的假期,小組長(zhǎng)有權(quán)力批準(zhǔn),3天以上的假期就要找更高級(jí)別的領(lǐng)導(dǎo)批準(zhǔn)。這種制度就是典型的權(quán)力越大職責(zé)越大——畢竟,批長(zhǎng)假的職責(zé)只在高級(jí)主管那里存在。

除了規(guī)定出這樣細(xì)致的要求之外,大部分公司還有用軟件實(shí)現(xiàn)了請(qǐng)假流程,當(dāng)請(qǐng)假人員提出請(qǐng)假申請(qǐng)的時(shí)候,會(huì)依據(jù)請(qǐng)假天數(shù),轉(zhuǎn)發(fā)給具有權(quán)限的人員審批,讓我們看看這個(gè)系統(tǒng)的代碼實(shí)現(xiàn)吧。

請(qǐng)假系統(tǒng)實(shí)現(xiàn)

在這個(gè)系統(tǒng)中,我們假定:

  • 小組長(zhǎng)可以審批3天以內(nèi)的請(qǐng)假請(qǐng)求
  • 部門(mén)經(jīng)理可以審批5天以內(nèi)的請(qǐng)假請(qǐng)求
  • 10天以內(nèi)的請(qǐng)假請(qǐng)求只有老板才能審批
  • 我們同時(shí)假定,這個(gè)公司的管理層非常人性化,請(qǐng)假都能得到批準(zhǔn),除非大于10天,因?yàn)檫@種情況沒(méi)人可以審批 

請(qǐng)假申請(qǐng)

這是最簡(jiǎn)單的類(lèi),封裝了請(qǐng)假天數(shù)和請(qǐng)假申請(qǐng)人

class VacationRequest
{
  public int DayNum { get; set; }
  public string RequesterName { get; set; }
}

假期審批者

首先創(chuàng)建一個(gè)抽象類(lèi),假期審批者,封裝假期審批的基本邏輯,即,如果當(dāng)前人員有權(quán)限審批當(dāng)前假期申請(qǐng),就處理

abstract class VacationApprover
{    
  protected VacationApprover(int dayCanHandle)
  {
    DayCanHandle = dayCanHandle;
  }

  public int DayCanHandle { get; protected set; }

  public void HandleVacationRequest(VacationRequest request)
  {
    if (request.DayNum <= DayCanHandle)
    {
      DoHandleVacationRequest(request);
    }
  }

  protected abstract void DoHandleVacationRequest(VacationRequest request);
}

當(dāng)然,抽象類(lèi)只需要確定算法骨架,限定只有當(dāng)前人員能處理這個(gè)請(qǐng)求的時(shí)候,才進(jìn)行審批工作,至于具體的審批實(shí)現(xiàn),留給子類(lèi)自己去覆蓋,這種在父類(lèi)固定算法骨架,暴露部分覆蓋點(diǎn)給子類(lèi)的做法,就是之前我們提到過(guò)的TemplateMethod模式

具體假期審批者

小組長(zhǎng),部門(mén)經(jīng)理,老板,都在這里創(chuàng)建,他們分別處理能審批3、5、10天的請(qǐng)假申請(qǐng)

class TeamLeader : VacationApprover
{
  private const int DAY_CAN_HANDLE_TEAMLEADER = 3;
  public TeamLeader() : base(DAY_CAN_HANDLE_TEAMLEADER) { }

  protected override void DoHandleVacationRequest(VacationRequest request)
  {
    Console.WriteLine("Now team leader handle this request");
    Console.WriteLine("Team leader accept this request");
  }
}

class DepartmentLeader : VacationApprover
{
  private const int DAY_CAN_HANDLE_DEPARTMENTLEADER = 5;
  public DepartmentLeader() : base(DAY_CAN_HANDLE_DEPARTMENTLEADER) { }

  protected override void DoHandleVacationRequest(VacationRequest request)
  {
    Console.WriteLine("Now department leader handle this request");
    Console.WriteLine("Department leader accept this request");
  }
}

class Boss : VacationApprover
{
  private const int DAY_CAN_HANDLE_BOSS = 10;
  public Boss() : base(DAY_CAN_HANDLE_BOSS) { }

  protected override void DoHandleVacationRequest(VacationRequest request)
  {
    Console.WriteLine("Now boss handle this request");
    Console.WriteLine("Boss accept this request");
  }
}

請(qǐng)假審批系統(tǒng)

請(qǐng)假審批系統(tǒng)提供統(tǒng)一請(qǐng)假申請(qǐng)接口,內(nèi)部通過(guò)請(qǐng)假天數(shù)決定哪個(gè)審批者參與審批

class VacationApproveSystem
{
  private VacationApprover teamLeader = new TeamLeader();
  private VacationApprover departmentLeader = new DepartmentLeader();
  private VacationApprover boss = new Boss();

  public void HandleVacationRequest(VacationRequest request)
  {
    Console.WriteLine("Now handle {0}'s {1} days' vacation request", request.RequesterName, request.DayNum);

    if (request.DayNum <= teamLeader.DayCanHandle)
    {
      teamLeader.HandleVacationRequest(request);
    }
    else if (request.DayNum <= departmentLeader.DayCanHandle)
    {
      departmentLeader.HandleVacationRequest(request);
    }
    else if (request.DayNum <= boss.DayCanHandle)
    {
      boss.HandleVacationRequest(request);
    }
    else
    {
      Console.WriteLine("Cannot handle this request after all");
    }
  }
}

測(cè)試代碼

class Program
{
  static void Main(string[] args)
  {
    VacationApproveSystem system = new VacationApproveSystem();

    system.HandleVacationRequest(new VacationRequest() { DayNum = 5, RequesterName = "laohu" });

    system.HandleVacationRequest(new VacationRequest() { DayNum = 10, RequesterName = "laohu" });

    system.HandleVacationRequest(new VacationRequest() { DayNum = 12, RequesterName = "laohu" });
  }
}

結(jié)果顯示

一切都是正常的,當(dāng)5天時(shí),部門(mén)經(jīng)理審批,10天時(shí),老板審批,大于10天無(wú)人能批。 Good job。

回頭看看

實(shí)現(xiàn)了第一版代碼之后,我們?cè)倩剡^(guò)頭看看,雖然代碼功能無(wú)誤,但是VacationApproveSystem似乎承擔(dān)了過(guò)多的職責(zé),它不但需要提供統(tǒng)一的請(qǐng)假審批接口給最終用戶,它同時(shí)還需要知道每個(gè)請(qǐng)假審批者能審批的請(qǐng)假天數(shù)并在內(nèi)部實(shí)現(xiàn)請(qǐng)假請(qǐng)求轉(zhuǎn)發(fā)給不同審批者的邏輯。這樣既違反了迪米特法則——它知道的太多了,也違反了開(kāi)閉原則——如果任何一個(gè)審批者修改了自身能審批的請(qǐng)假天數(shù),這個(gè)類(lèi)都會(huì)被波及,最后,它還違反了單一職責(zé)——一個(gè)類(lèi)只能有一個(gè)引起變化的原因。

有鑒于此,我們這版代碼只能算湊合用,但遠(yuǎn)遠(yuǎn)談不上結(jié)構(gòu)良好,老老實(shí)實(shí)地重構(gòu)代碼吧,下面請(qǐng)出我們今天的主角。

職責(zé)鏈模式

解耦具體對(duì)象和請(qǐng)求,使得多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求。將對(duì)象連成一條鏈,沿著鏈傳遞請(qǐng)求直到有對(duì)象處理它

乍一聽(tīng)有點(diǎn)生澀,翻譯一下就是

  • 解耦具體對(duì)象和請(qǐng)求——不要預(yù)先指定哪個(gè)對(duì)象來(lái)處理此請(qǐng)求(因?yàn)楹芏鄷r(shí)候并不知道)
  • 使多個(gè)對(duì)象都有機(jī)會(huì)——有一眾候選對(duì)象,具體使用哪個(gè)對(duì)象是在運(yùn)行時(shí)決定的
  • 連成鏈傳遞請(qǐng)求——像鏈表一樣,要在對(duì)象中體現(xiàn)出對(duì)象之間的鏈關(guān)系,而不要通過(guò)其他類(lèi)以if..else的方式實(shí)現(xiàn)

所以,這么看來(lái)這個(gè)模式和我們的例子簡(jiǎn)直是絕配,我們已經(jīng)做了大部分的工作了,現(xiàn)在剩下的就只是修改審批者,讓審批者能鏈起來(lái) 

代碼重構(gòu)

修改請(qǐng)假審批基類(lèi)
最重要的改動(dòng),就是修改基類(lèi),讓對(duì)象能鏈起來(lái),在VacationApprover中添加一個(gè)后繼節(jié)點(diǎn)和一個(gè)設(shè)置后繼節(jié)點(diǎn)的方法。同時(shí)在基類(lèi)的審批方法中,完成請(qǐng)求傳遞,即,如果請(qǐng)假申請(qǐng)超過(guò)了當(dāng)前審批人的能力范圍,則轉(zhuǎn)發(fā)至后繼節(jié)點(diǎn)。修改后的類(lèi)如下

abstract class VacationApprover
{
  private VacationApprover nextVacationApprover = null;

  public void SetNextVacationApprover(VacationApprover approver)
  {
    nextVacationApprover = approver;
  }

  protected VacationApprover(int dayCanHandle)
  {
    DayCanHandle = dayCanHandle;
  }

  public int DayCanHandle { get; protected set; }

  public void HandleVacationRequest(VacationRequest request)
  {
    if (request.DayNum <= DayCanHandle)
    {
      DoHandleVacationRequest(request);
    }
    else
    {
      if(nextVacationApprover != null)
      {
        nextVacationApprover.HandleVacationRequest(request);
      }
      else
      {
        Console.WriteLine("Cannot handle this request after all");
      }
    }
  }

  protected abstract void DoHandleVacationRequest(VacationRequest request);
}

修改請(qǐng)假審批系統(tǒng)

基類(lèi)重構(gòu)結(jié)束之后,請(qǐng)假審批系統(tǒng)就可以瘦身了,刪除了所有判斷邏輯,僅僅在構(gòu)造函數(shù)里面完成鏈組建的工作,接著一鍵調(diào)用,齊活。

class VacationApproveSystem
{
  private VacationApprover teamLeader = new TeamLeader();
  private VacationApprover departmentLeader = new DepartmentLeader();
  private VacationApprover boss = new Boss();

  public VacationApproveSystem()
  {
    teamLeader.SetNextVacationApprover(departmentLeader);
    departmentLeader.SetNextVacationApprover(boss);
  }

  public void HandleVacationRequest(VacationRequest request)
  {
    Console.WriteLine("Now handle {0}'s {1} days' vacation request", request.RequesterName, request.DayNum);

    teamLeader.HandleVacationRequest(request);
  }
}

測(cè)試

其他請(qǐng)假審批子類(lèi)和測(cè)試客戶端都不需要改動(dòng),這次重構(gòu)工作量非常小,運(yùn)行代碼,一切正常,重構(gòu)成功。

總結(jié)

這就是職責(zé)鏈模式的使用。和狀態(tài)模式有點(diǎn)像,解決了以下問(wèn)題:

  • 通過(guò)添加子類(lèi)把一些邏輯判斷從調(diào)用類(lèi)(VaccationApproveSystem)移到子類(lèi)的方式,使得調(diào)用類(lèi)滿足迪米特法則
  • 想在職責(zé)鏈上面添加更多節(jié)點(diǎn)的時(shí)候,只需要添加新類(lèi)和修改鏈組裝部分的代碼,基本滿足開(kāi)閉原則(這里幾乎不可能完全滿足開(kāi)閉原則,畢竟有修改就意味著我們肯定會(huì)改動(dòng)VaccationApproveSystem類(lèi),只是我們應(yīng)該盡量的讓代碼改動(dòng)量少,以提高控制代碼變動(dòng)的能力)

和狀態(tài)模式一樣,它也有子類(lèi)爆炸的風(fēng)險(xiǎn)。

可能有朋友會(huì)感到疑惑,既然職責(zé)鏈模式和狀態(tài)模式看起來(lái)那么像,那它們有什么區(qū)別呢?它們的區(qū)別在于:

  • 狀態(tài)模式中的對(duì)象是有狀態(tài)的,可以隨時(shí)通過(guò)接口查詢對(duì)象的當(dāng)前狀態(tài),對(duì)象正是因?yàn)橛辛瞬煌臓顟B(tài),才會(huì)表現(xiàn)出不同行為。而職責(zé)鏈模式中的對(duì)象沒(méi)有狀態(tài),對(duì)象和鏈的關(guān)系更像請(qǐng)求和處理管線的關(guān)系,沒(méi)有接口能告訴我們當(dāng)前在處理管線的哪個(gè)節(jié)點(diǎn),也沒(méi)有意義這么做,我們只關(guān)心請(qǐng)求是否被處理了
  • 狀態(tài)模式中的狀態(tài)切換可以是無(wú)序的,比如,一個(gè)游戲角色,當(dāng)他的狀態(tài)是虛弱的時(shí)候,可以通過(guò)治療,轉(zhuǎn)換成健康,也可以通過(guò)受傷轉(zhuǎn)換成瀕死。而職責(zé)鏈中的請(qǐng)求轉(zhuǎn)發(fā)就只有向前一條路,從小組長(zhǎng)到部門(mén)經(jīng)理,從部門(mén)經(jīng)理到老板

根據(jù)不同的情景,選擇合適的模式,才是正確的使用之道。以上就是今天的內(nèi)容,希望大家喜歡,我們下次見(jiàn)!

以上就是實(shí)例講解C#中的職責(zé)鏈模式的詳細(xì)內(nèi)容,更多關(guān)于C# 職責(zé)鏈模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 淺談C# 字段和屬性

    淺談C# 字段和屬性

    這篇文章主要介紹了C# 字段和屬性的的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • C#中常見(jiàn)警告類(lèi)型及處理方法詳解

    C#中常見(jiàn)警告類(lèi)型及處理方法詳解

    在C#開(kāi)發(fā)過(guò)程中,常常會(huì)遇到各種各樣的警告信息,本文將結(jié)合多種常見(jiàn)情況,詳細(xì)介紹如何處理C#中的一些典型警告,希望對(duì)大家有所幫助
    2024-11-11
  • 基于C#實(shí)現(xiàn)FTP下載文件

    基于C#實(shí)現(xiàn)FTP下載文件

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)FTP下載文件,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • c# 實(shí)現(xiàn)發(fā)送郵件的功能

    c# 實(shí)現(xiàn)發(fā)送郵件的功能

    這篇文章主要介紹了c# 如何實(shí)現(xiàn)發(fā)送郵件的功能,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • C# DataTable中Compute方法用法集錦(數(shù)值/字符串/運(yùn)算符/表等操作)

    C# DataTable中Compute方法用法集錦(數(shù)值/字符串/運(yùn)算符/表等操作)

    這篇文章主要介紹了C# DataTable中Compute方法用法,總結(jié)分析了DataTable中Compute方法常見(jiàn)的數(shù)值運(yùn)算操作、字符串操作、運(yùn)算符操作、表運(yùn)算等相關(guān)技巧,需要的朋友可以參考下
    2016-06-06
  • c# 獲取數(shù)據(jù)庫(kù)中所有表名稱的方法

    c# 獲取數(shù)據(jù)庫(kù)中所有表名稱的方法

    在很多情況下我們需要將指定的數(shù)據(jù)庫(kù)中的所有表都列出來(lái)。在使用c#進(jìn)行軟件開(kāi)發(fā)時(shí),我們有哪些方法可是實(shí)現(xiàn)這個(gè)目的呢?本人對(duì)此進(jìn)行概要的總結(jié),有以下6中方式可以實(shí)現(xiàn)這個(gè)目的。
    2010-02-02
  • 如何在c#中使用opencv函數(shù)庫(kù)

    如何在c#中使用opencv函數(shù)庫(kù)

    這篇文章主要介紹了如何在c#中使用opencv,對(duì)圖像匹配處理感興趣的同學(xué)可以參考下
    2021-04-04
  • C#在foreach遍歷刪除集合中元素的三種實(shí)現(xiàn)方法

    C#在foreach遍歷刪除集合中元素的三種實(shí)現(xiàn)方法

    這篇文章主要給大家總結(jié)介紹了關(guān)于C#在foreach遍歷刪除集合中元素的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • C# 異步多線程入門(mén)到精通之ThreadPool篇

    C# 異步多線程入門(mén)到精通之ThreadPool篇

    ThreadPool 是 .net 2.0 時(shí)代的產(chǎn)物,有了 Thread 為什么還會(huì)有 ThreadPool 呢?ThreadPool 可以做到限制線程數(shù)量、重用線程
    2021-11-11
  • C#結(jié)束進(jìn)程及子進(jìn)程

    C#結(jié)束進(jìn)程及子進(jìn)程

    這篇文章介紹了C#操作結(jié)束進(jìn)程及子進(jìn)程的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06

最新評(píng)論

三穗县| 蒲城县| 武隆县| 淳化县| 祁门县| 沾益县| 荣昌县| 谷城县| 偃师市| 扬中市| 沙河市| 辉南县| 新营市| 多伦县| 罗平县| 莱阳市| 通榆县| 六枝特区| 金坛市| 木里| 台南县| 大方县| 江西省| 普洱| 舞钢市| 左权县| 新兴县| 沛县| 甘洛县| 高密市| 福贡县| 讷河市| 彰化县| 鸡东县| 卢氏县| 筠连县| 杭锦后旗| 汉寿县| 区。| 石首市| 屯昌县|