温故知新(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、运行,查看结果。