设计模式之三职责链模式

      本文中,我们将介绍设计模式中的行为型模式职责链模式,职责链模式的结果看上去很简单,但是也很复杂。首先我们来了解下现实生活中的链子,如下图:

 了解职责链之前我们先来了解下职责链模式的模式动机:

 

模式动机

  职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。
 
  链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并使请求沿着链传递,由链上的处理者对请求进行相应的处理,
 
客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,将请求的发送者和请求的处理者解耦。这就是职责链模式的模式动机。
 
 

模式定义

      职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链
 
并且沿着这条链传递请求,直到有对象处理它为止。由于英文翻译的不同,职责链模式又称为责任链模式,它是一种对象行为型模式
 

 模式结构

 

职责链模式包含如下角色:
Handler: 抽象处理者:定义出一个处理请求的接口。如果需要,接口可以定义出一个方法,以设定和返回对下家的引用。这个角色通常由一个抽象类或接口实现。
ConcreteHandler: 具体处理者:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
Client: 客户端

 

下面我们通过具体的例子来分析说明如何使用职责链模式:

审批假条
•某OA系统需要提供一个假条审批的模块,如果员工请假天数小于10天,TeamLeader可以审批该假条;如果员工请假天数大于等于10天,小于20天,项目经理可以审批;如果员工请假天数大于等于20天,小于30天,HR可以审批。大于30天无法审批!
 
 
在解决方案中新建如下角色:

 

 定义抽象处理者:

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChainOfResponsibilityDemo.ActionItem;

namespace ChainOfResponsibilityDemo.Handler
{
    public abstract class Employee
    {
        /// <summary>
        /// 委托
        /// </summary>
        /// <param name="e"></param>
        /// <param name="l"></param>
        public delegate void OnLeaveApplied(Employee e, Leave l);
        /// <summary>
        /// 事件
        /// </summary>
        public event OnLeaveApplied onLeaveApplied = null;

        public void LeaveApplied(Employee s, Leave leave)
        {
            if (onLeaveApplied != null)
            {
                onLeaveApplied(this, leave);
            }
        }

        /// <summary>
        /// 抽象方法
        /// </summary>
        /// <param name="leave"></param>
        public abstract void ApproveLeave(Leave leave);
        /// <summary>
        /// 定义属性 员工的上级管理者
        /// </summary>
        public Employee Supervisor
        {
            get;
            set;
        }

        public void ApplyLeave(Leave l)
        {
            LeaveApplied(this, l);
        }
    }
}

 

定义员工级别:

View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace ChainOfResponsibilityDemo.ActionItem
 7 {
 8     /// <summary>
 9     /// 定义员工级别
10     /// </summary>
11     public class Leave
12     {
13         /// <summary>
14         /// 构造函数
15         /// </summary>
16         /// <param name="guid"></param>
17         /// <param name="days"></param>
18         public Leave(Guid guid, int days)
19         {
20             leaveID = guid;
21             numberOfDays = days;
22         }
23 
24         Guid leaveID;
25         /// <summary>
26         /// 级别
27         /// </summary>
28         public Guid LeaveID
29         {
30             get { return leaveID; }
31             set { leaveID = value; }
32         }
33         int numberOfDays;
34 
35         /// <summary>
36         /// 请假天数
37         /// </summary>
38         public int NumberOfDays
39         {
40             get { return numberOfDays; }
41             set { numberOfDays = value; }
42         }
43     }
44 }

定义具体处理者:

TeamLeader:

View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using ChainOfResponsibilityDemo.Handler;
 6 using ChainOfResponsibilityDemo.ActionItem;
 7 
 8 namespace ChainOfResponsibilityDemo.ConcreteHandlers
 9 {
10     /// <summary>
11     /// TeamLeader
12     /// </summary>
13     public class TeamLeader:Employee
14     {
15         /// <summary>
16         /// 最大请假天数
17         /// </summary>
18         const int MAX_LEAVES_CAN_APPROVE = 10;
19 
20         public TeamLeader()
21         {
22             this.onLeaveApplied+=new OnLeaveApplied(TeamLeader_onLeaveApplied);
23         }
24 
25         protected void TeamLeader_onLeaveApplied(Employee e, Leave l)
26         {
27             //如果请假天数小于 teamleader可以批准的天数,直接批假
28             if (l.NumberOfDays < MAX_LEAVES_CAN_APPROVE)
29             {
30                 ApproveLeave(l);
31             }
32             else
33             {
34                 if (Supervisor != null)
35                 {
36                     //请上级批假
37                     Supervisor.LeaveApplied(this, l);
38                 }
39             }
40         }
41 
42         //批假
43         public override void ApproveLeave(Leave leave)
44         {
45             Console.WriteLine("LeaveID: {0} Days: {1} Approver: {2}",
46                leave.LeaveID, leave.NumberOfDays, "Team Leader");
47         }
48     }
49 }

ProjectLeader:

View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using ChainOfResponsibilityDemo.Handler;
 6 using ChainOfResponsibilityDemo.ActionItem;
 7 
 8 namespace ChainOfResponsibilityDemo.ConcreteHandlers
 9 {
10     /// <summary>
11     /// 项目经理
12     /// </summary>
13     public class ProjectLeader:Employee
14     {
15         /// <summary>
16         /// 最大请假天数
17         /// </summary>
18         const int MAX_LEAVES_CAN_APPROVE = 20;
19 
20         public ProjectLeader()
21         {
22             this.onLeaveApplied+=new OnLeaveApplied(ProjectLeader_onLeaveApplied);
23         }
24 
25 
26         protected void ProjectLeader_onLeaveApplied(Employee e, Leave l)
27         {
28             //如果请假天数小于 teamleader可以批准的天数,直接批假
29             if (l.NumberOfDays < MAX_LEAVES_CAN_APPROVE)
30             {
31                 ApproveLeave(l);
32             }
33             else
34             {
35                 if (Supervisor != null)
36                 {
37                     //请上级批假
38                     Supervisor.LeaveApplied(this, l);
39                 }
40             }
41         }
42 
43         public override void ApproveLeave(Leave leave)
44         {
45             Console.WriteLine("LeaveID: {0} Days: {1} Approver: {2}",
46                 leave.LeaveID, leave.NumberOfDays, "Project Leader");
47         }
48     }
49 }

HR:

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChainOfResponsibilityDemo.Handler;
using ChainOfResponsibilityDemo.ActionItem;

namespace ChainOfResponsibilityDemo.ConcreteHandlers
{
    public class HR:Employee
    {
        /// <summary>
        /// 最大请假天数
        /// </summary>
        const int MAX_LEAVES_CAN_APPROVE = 30;

        public HR()
        {
            this.onLeaveApplied += new OnLeaveApplied(HR_onLeaveApplied);
        }

       
        void HR_onLeaveApplied(Employee e, Leave l)
        {
            
            if (l.NumberOfDays < MAX_LEAVES_CAN_APPROVE)
            {
                ApproveLeave(l);
            }
            else
            {
               
                if (Supervisor != null)
                {
                    Supervisor.LeaveApplied(this, l);
                }
                else
                {
                    Console.WriteLine("您的假期超过最高限制,请联系HR!");
                }
            }
        }


        public override void ApproveLeave(Leave leave)
        {
            Console.WriteLine("LeaveID: {0} Days: {1} Approver: {2}",
                leave.LeaveID, leave.NumberOfDays, "HR");
        }
    }
}

 

客户端调用:

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChainOfResponsibilityDemo.ConcreteHandlers;
using ChainOfResponsibilityDemo.ActionItem;

namespace ChainOfResponsibilityDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建员工对象
            TeamLeader tl = new TeamLeader();
            ProjectLeader pl = new ProjectLeader();
            HR hr = new HR();

            //设置员工上级
            tl.Supervisor = pl;
            pl.Supervisor = hr;

            //请假5天
            tl.ApplyLeave(new Leave(Guid.NewGuid(), 5));

            //请假15天
            tl.ApplyLeave(new Leave(Guid.NewGuid(), 15));

            //请假25天
            tl.ApplyLeave(new Leave(Guid.NewGuid(), 25));

            //请假35天
            tl.ApplyLeave(new Leave(Guid.NewGuid(), 35));

            Console.ReadLine();
        }
    }
}


输出结果:

 

模式分析

在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链
 
请求在这条链上传递,直到链上的某一个对象处理此请求为止。
 
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任
 
 

模式优缺点

职责链模式的优点

• 降低耦合度
 
• 可简化对象的相互连接
 
• 增强给对象指派职责的灵活性
 
• 增加新的请求处理类很方便
 

职责链模式的缺点

•不能保证请求一定被接收。
 
•系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。
 

模式适用环境

在以下情况下可以使用职责链模式:

•有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
 
•在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
 
•可动态指定一组对象处理请求。
 

总结

    行为型模式是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。通过行为型模式,可以更加清晰地划
 
分类与对象的职责,并研究系统在运行时实例对象之间的交互。行为型模式可以分为类行为型模式和对象行为型模式两种。
 
    职责链模式可以避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。它是一种对象行为型模式。
 
    职责链模式包含两个角色:抽象处理者定义了一个处理请求的接口;具体处理者是抽象处理者的子类,它可以处理用户请求。
 
    在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知
 
道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
 
     职责链模式的主要优点在于可以降低系统的耦合度,简化对象的相互连接,同时增强给对象指派职责的灵活性,增加新的请求处理类也很方便;其主要缺点在于不能保证请求一
 
定被接收,且对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
 
     职责链模式适用情况包括:有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定;在不明确指定接收者的情况下,向多个对象中的一个提交
一个请求;可动态指定一组对象处理请求。
 
posted @ 2012-11-29 14:21  vito qi  阅读(10149)  评论(2编辑  收藏  举报