溫故知新(7)——職責鏈模式


概述

初次聽到職責鏈這個名詞,你或許會有一種高深莫測的感覺,我當時就是這樣。但如果深入的看下去,發現職責鏈還真是顧名思義,就是一系列具有相同職責的對象構成一個對象鏈,由這個對象鏈去處理一個請求。發出請求的客戶端只需知道這個鏈可以處理這個請求,無需知道這個鏈的構成和排列。照例給出GOF的意圖描述:

使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它為止。

職責鏈模式有兩個要點:

1、存在多個請求的接收者;

2、多個接收者依次處理請求,此處包含了順序的要求;

3、具體由哪個或哪些接收者處理這個請求可以在運行時決定;

在我理解GOF的意圖描述,暗含了接收者要嘛處理請求,要嘛轉交請求,也就是所謂的純職責鏈。但我認為實際環境中應用更多的應該是非純職責鏈,也就是每個接收者對象完成自己的處理操作,然后轉交給下一個接收者。就像switch語句中的defult一樣,實現時我們也應該提供一個defult接收者,以防止沒有接收者處理請求而出錯。關於純職責鏈與非純職責鏈的描述可以參看(http://blog.csdn.net/lovelion/article/details/7420902)。

職責鏈模式對發送請求的客戶與接收請求的接收者進行的了解偶,同時為多個接收者的組織提供較大的靈活性。但是當職責鏈較長時應該考慮效率問題,實現時也應注意避免鏈閉合造成無限循環。

結構

職責鏈模式的類圖:

職責鏈

模式的參與者:

1、定義接受者共同職責的接口——IHandler;

2、接受者的具體實現——HandlerA,HandlerB;

3、客戶端程序——Client;

注意IHandler上的自引用,IHandler通常會包含職責鏈下一環的引用。如果自引用的重數為1時,上圖表示的就是經典的職責鏈;當重數為0…*時“職責鏈”就演化為“職責樹”。關於職責樹變體,讀者可自行思考。

示例

本示例取自一個基金銷售系統。為了吸引用戶購買,系統通常需要為基金給出一些推薦標簽,如果基金曾經獲獎那么給出“獲獎基金”的標簽,如果業績出色那么給出“業績優秀”的標簽;如果基金的規模比較大那么給出“規模大”的標簽;如果某基金確實沒有什么亮點,那么給一個默認的“在售”標簽。這些標簽的重要性依次降低。

考慮到,給出每種的標簽的處理程序職責相同(給予或不給予標簽)算法不不同,而且標簽有順序要求,未來這些處理程序可能有增減,因此使用職責鏈模式比較合適。

1、標簽處理接口ILabelProcessor。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.ChainOfResponsibility
 4:  {
 5:      /// <summary>
 6:      /// 職責接口,所有處理者須實現
 7:      /// </summary>
 8:      public interface ILabelProcessor
 9:      {
10:          ILabelProcessor Successor { get; set; }
11:          void TakeLabel(Fund fund);
12:      }
13:  }
14:   

2、標簽處理的幾個具體實現。

首先是一個抽象類AbstractLabelProcessor,用來處理公用的Successor。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.ChainOfResponsibility
 4:  {
 5:      /// <summary>
 6:      /// 處理者抽象類
 7:      /// </summary>
 8:      public abstract class AbstractLabelProcessor : ILabelProcessor
 9:      {
10:          public AbstractLabelProcessor(ILabelProcessor successor)
11:          {
12:              this.successor = successor;
13:          }
14:   
15:          protected ILabelProcessor successor;
16:   
17:          /// <summary>
18:          /// 后續處理者
19:          /// </summary>
20:          public ILabelProcessor Successor
21:          {
22:              get
23:              {
24:                  return this.successor;
25:              }
26:              set
27:              {
28:                  this.successor = value;
29:              }
30:          }
31:   
32:          public abstract void TakeLabel(Fund fund);
33:      }
34:  }
35:   

“獲獎情況”處理者PrizeLabelProcessor。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.ChainOfResponsibility
 4:  {
 5:      /// <summary>
 6:      /// “獲獎情況”處理者
 7:      /// </summary>
 8:      public class PrizeLabelProcessor : AbstractLabelProcessor
 9:      {
10:          public PrizeLabelProcessor(ILabelProcessor successor)
11:              : base(successor)
12:          { }
13:   
14:          public override void TakeLabel(Fund fund)
15:          {
16:              if (fund.Code == "100001" || fund.Code == "100002")
17:              {
18:                  fund.Labels.Add("獲獎基金");
19:              }
20:              if (this.successor != null)
21:              {
22:                  this.successor.TakeLabel(fund);
23:              }
24:          }
25:      }
26:  }
27:   

“業績”處理者PerformanceLabelProcessor。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.ChainOfResponsibility
 4:  {
 5:      /// <summary>
 6:      /// “業績”處理者
 7:      /// </summary>
 8:      public class PerformanceLabelProcessor : AbstractLabelProcessor
 9:      {
10:          public PerformanceLabelProcessor(ILabelProcessor successor)
11:              : base(successor)
12:          { }
13:   
14:          public override void TakeLabel(Fund fund)
15:          {
16:              if (fund.Code == "100002" || fund.Code == "100003")
17:              {
18:                  fund.Labels.Add("業績優秀");
19:              }
20:              if (this.successor != null)
21:              {
22:                  this.successor.TakeLabel(fund);
23:              }
24:          }
25:      }
26:  }
27:   

“規模”處理者SizeLabelProcessor。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.ChainOfResponsibility
 4:  {
 5:      /// <summary>
 6:      /// “規模”處理者
 7:      /// </summary>
 8:      public class SizeLabelProcessor : AbstractLabelProcessor
 9:      {
10:          public SizeLabelProcessor(ILabelProcessor successor)
11:              : base(successor)
12:          { }
13:   
14:          public override void TakeLabel(Fund fund)
15:          {
16:              if (fund.Code == "100001" || fund.Code == "100003")
17:              {
18:                  fund.Labels.Add("規模大");
19:              }
20:              if (this.successor != null)
21:              {
22:                  this.successor.TakeLabel(fund);
23:              }
24:          }
25:      }
26:  }
27:   

“默認”處理者DefaultLabelProcessor。默認處理者總是處於職責鏈的末端,所以它沒有后繼處理者。當沒有任何標簽時,給出默認標簽“在售”。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.ChainOfResponsibility
 4:  {
 5:      /// <summary>
 6:      /// “默認”處理者
 7:      /// </summary>
 8:      public class DefaultLabelProcessor : AbstractLabelProcessor
 9:      {
10:          public DefaultLabelProcessor()
11:              : base(null)
12:          { }
13:   
14:          public override void TakeLabel(Fund fund)
15:          {
16:              if (fund.Labels.Count == 0)
17:              {
18:                  fund.Labels.Add("在售");
19:              }
20:          }
21:      }
22:  }
23:   

3、表示基金的實體類Fund。這里僅保留了很少的內容,實際中此類還包含很多其它信息。

 1:  using System;
 2:  using System.Collections.Generic;
 3:   
 4:  namespace DesignPatterns.ChainOfResponsibility
 5:  {
 6:      /// <summary>
 7:      /// 表示基金的實體類
 8:      /// </summary>
 9:      public class Fund
10:      {
11:          public Fund(string code)
12:          {
13:              this.Code = code;
14:              this.Labels = new List<string>();
15:          }
16:   
17:          /// <summary>
18:          /// 代碼
19:          /// </summary>
20:          public string Code { get; set; }
21:   
22:          /// <summary>
23:          /// 標簽
24:          /// </summary>
25:          public List<string> Labels { get; set; }
26:      }
27:  }
28:   

4、客戶端代碼。

 1:  using System;
 2:  using System.Collections.Generic;
 3:   
 4:  namespace DesignPatterns.ChainOfResponsibility
 5:  {
 6:      class Program
 7:      {
 8:          static void Main(string[] args)
 9:          {
10:              //職責鏈構造
11:              ILabelProcessor defaultLabelProcessor = new DefaultLabelProcessor(); //默認處理者總是處於鏈的末端。
12:              ILabelProcessor sizeLabelProcessor = new SizeLabelProcessor(defaultLabelProcessor);
13:              ILabelProcessor performanceLabelProcessor = new PerformanceLabelProcessor(sizeLabelProcessor);
14:              ILabelProcessor prizeLabelProcessor = new PrizeLabelProcessor(performanceLabelProcessor);
15:   
16:              //客戶端無需了解處理對象的具體情況
17:              ILabelProcessor processor = prizeLabelProcessor;
18:   
19:              string[] codes = { "100001", "100002", "100003", "100004" };
20:              foreach (var code in codes)
21:              {
22:                  Fund fund = new Fund(code);
23:                  processor.TakeLabel(fund);
24:                  Display(fund);
25:              }
26:   
27:              Console.WriteLine("按任意鍵結束...");
28:              Console.ReadKey();
29:          }
30:   
31:          //展示
32:          private static void Display(Fund fund)
33:          {
34:              Console.Write(fund.Code + ":");
35:              foreach (var label in fund.Labels)
36:              {
37:                  Console.Write(label + " ");
38:              }
39:              Console.WriteLine();
40:              Console.WriteLine("=========================");
41:          }
42:      }
43:  }
44:   

5、運行,查看結果。

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM