【21】責任鏈模式

  1、引言html

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

  2、責任鏈模式介紹app

  2.1 責任鏈模式的定義ide

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

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

  2.2 責任鏈模式的結構圖spa

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

  
  主要涉及兩個角色:code

  1)抽象處理者角色(Handler):定義出一個處理請求的接口。這個接口一般由接口或抽象類來實現。htm

  2)具體處理者角色(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();
        }
    }
}

  原來的設計會由於價格條件範圍的變化而致使不利於擴展,根據「封裝變化」的原則,此時咱們想的天然是能不能把價格範圍細化到不一樣的類中呢?由於每一個價格範圍都決定某個批准者,這裏就聯想到建立多個批准類,這樣每一個類中只須要針對他本身這個範圍的價格判斷。這樣也就是責任鏈的最後實現方式了,具體的運行結果以下圖所示:

  3、責任鏈模式的適用場景

  在如下場景中能夠考慮使用責任鏈模式:

  1)一個系統的審批須要多個對象才能完成處理的狀況下,例如請假系統等。

  2)代碼中存在多個if-else語句的狀況下,此時能夠考慮使用責任鏈模式來對代碼進行重構。

  4、責任鏈模式的優缺點

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

  1)下降了請求的發送者和接收者之間的耦合。

  2)把多個條件斷定分散到各個處理類中,使得代碼更加清晰,責任更加明確。

  責任鏈模式也具備必定的缺點,如:

  1)在找到正確的處理對象以前,全部的條件斷定都要執行一遍,當責任鏈過長時,可能會引發性能的問題。

  2)可能致使某個請求不被處理。

  5、總結

  責任鏈下降了請求端和接收端之間的耦合,使多個對象都有機會處理某個請求。

 

參考連接:http://www.cnblogs.com/zhili/p/ChainOfResponsibity.html

相關文章
相關標籤/搜索