C#設計模式(21)——責任鏈模式

來源:互聯網
上載者:User

標籤:manager   缺點   導致   存在   角色   ade   解決   sts   bsp   

原文:C#設計模式(21)——責任鏈模式

一、引言

  在現實生活中,有很多請求並不是一個人說了就算的,例如面試時的工資,低於1萬的薪水可能技術經理就可以決定了,但是1萬~1萬5的薪水可能技術經理就沒這個權利批准,可能就需要請求技術總監的批准,所以在面試的完後,經常會有面試官說,你這個薪水我這邊覺得你這技術可以拿這個薪水的,但是還需要技術總監的批准等的話。這個例子也就詮釋了本文要介紹的內容。生活中的這個例子真是應用了責任鏈模式。

二、責任鏈模式介紹2.1 責任鏈模式的定義

  從生活中的例子可以發現,某個請求可能需要幾個人的審批,即使技術經理審批完了,還需要上一級的審批。這樣的例子,還有公司中的請假,少於3天的,直屬Leader就可以批准,3天到7天之內就需要專案經理批准,多餘7天的就需要技術總監的批准了。介紹了這麼多生活中責任鏈模式的例子的,下面具體給出物件導向中責任鏈模式的定義。

  責任鏈模式指的是——某個請求需要多個對象進行處理,從而避免請求的寄件者和接收之間的耦合關係。將這些對象連成一條鏈子,並沿著這條鏈子傳遞該請求,直到有對象處理它為止。

2.2 責任鏈模式的結構圖

  從責任鏈模式的定義可以發現,責任鏈模式涉及的對象只有處理者角色,但由於有多個處理者,它們具有共同的處理請求的方法,所以這裡抽象出一個抽象處理者角色進行代碼複用。這樣分析下來,責任鏈模式的結構圖也就不言而喻了,具體結構圖如下所示。

  主要涉及兩個角色:

  • 抽象處理者角色(Handler):定義出一個處理請求的介面。這個介面通常由介面或抽象類別來實現。
  • 具體處理者角色(ConcreteHandler):具體處理者接受到請求後,可以選擇將該請求處理掉,或者將請求傳給下一個處理者。因此,每個具體處理者需要儲存下一個處理者的引用,以便把請求傳遞下去。
2.3 責任鏈模式的實現

  有了上面的介紹,下面以公司採購東西為例子來實現責任鏈模式。公司規定,採購架構總價在1萬之內,經理層級的人批准即可,總價大於1萬小於2萬5的則還需要副總進行批准,總價大於2萬5小於10萬的需要還需要總經理批准,而大於總價大於10萬的則需要組織一個會議進行討論。對於這樣一個需求,最直觀的方法就是設計一個方法,參數是採購的總價,然後在這個方法內對價格進行調整判斷,然後針對不同的條件交給不同層級的人去處理,這樣確實可以解決問題,但這樣一來,我們就需要多重if-else語句來進行判斷,但當加入一個新的條件範圍時,我們又不得不去修改原來設計的方法來再添加一個條件判斷,這樣的設計顯然違背了“開-閉”原則。這時候,可以採用責任鏈模式來解決這樣的問題。具體實現代碼如下所示。

namespace ChainofResponsibility{    // 採購請求    public class PurchaseRequest    {        // 金額        public double Amount { get; set; }        // 產品名字        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);    }    // ConcreteHandler    public class Manager : Approver    {        public Manager(string name)            : base(name)        { }        public override void ProcessRequest(PurchaseRequest request)        {            if (request.Amount < 10000.0)            {                Console.WriteLine("{0}-{1} approved the request of purshing {2}", this, Name, request.ProductName);            }            else if (NextApprover != null)            {                NextApprover.ProcessRequest(request);            }        }    }    // ConcreteHandler,副總    public class VicePresident : Approver    {        public VicePresident(string name)            : base(name)        {         }        public override void ProcessRequest(PurchaseRequest request)        {            if (request.Amount < 25000.0)            {                Console.WriteLine("{0}-{1} approved the request of purshing {2}", this, Name, request.ProductName);            }            else if (NextApprover != null)            {                NextApprover.ProcessRequest(request);            }        }    }    // ConcreteHandler,總經理    public class President :Approver    {        public President(string name)            : base(name)        { }        public override void ProcessRequest(PurchaseRequest request)        {            if (request.Amount < 100000.0)            {                Console.WriteLine("{0}-{1} approved the request of purshing {2}", this, Name, request.ProductName);            }            else            {                Console.WriteLine("Request需要組織一個會議討論");            }        }    }    class Program    {        static void Main(string[] args)        {            PurchaseRequest requestTelphone = new PurchaseRequest(4000.0, "Telphone");            PurchaseRequest requestSoftware = new PurchaseRequest(10000.0, "Visual Studio");            PurchaseRequest requestComputers = new PurchaseRequest(40000.0, "Computers");            Approver manager = new Manager("LearningHard");            Approver Vp = new VicePresident("Tony");            Approver Pre = new President("BossTom");            // 設定責任鏈            manager.NextApprover = Vp;            Vp.NextApprover = Pre;            // 處理請求            manager.ProcessRequest(requestTelphone);            manager.ProcessRequest(requestSoftware);            manager.ProcessRequest(requestComputers);            Console.ReadLine();        }    }}

  既然,原來的設計會因為價格條件範圍的變化而導致不利於擴充,根據“封裝變化”的原則,此時我們想的自然是能不能把價格範圍細化到不同的類中呢?因為每個價格範圍都決定某個批准者,這裡就聯想到建立多個批准類,這樣每個類中只需要針對他自己這個範圍的價格判斷。這樣也就是責任鏈的最後實現方式了,具體的運行結果如所示。

三、責任鏈模式的適用情境 

  在以下情境中可以考慮使用責任鏈模式:

  • 一個系統的審批需要多個對象才能完成處理的情況下,例如請假系統等。
  • 代碼中存在多個if-else語句的情況下,此時可以考慮使用責任鏈模式來對代碼進行重構。
四、責任鏈模式的優缺點

  責任鏈模式的優點不言而喻,主要有以下點:

  • 降低了請求的寄件者和接收者之間的耦合。
  • 把多個條件判定分散到各個處理類中,使得代碼更加清晰,責任更加明確。

  責任鏈模式也具有一定的缺點,如:

  • 在找到正確的處理對象之前,所有的條件判定都要執行一遍,當責任鏈過長時,可能會引起效能的問題
  • 可能導致某個請求不被處理。
五、總結

  責任鏈降低了請求端和接收端之間的耦合,使多個對象都有機會處理某個請求。如考試中作弊傳紙條,泡妞傳情書一般。在下一章將繼續分享訪問者模式。

 

C#設計模式(21)——責任鏈模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.