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