设计模式学习笔记--Chain Of Responsibility 职责链模式

本文介绍职责链模式,一种用于解耦请求处理逻辑的设计模式。通过示例代码展示如何使用抽象处理者和具体处理者角色来建立请求处理链,适用于需要多级审批或处理流程的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   职责链模式是一种对象的行为模式【GOF95】。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
   引入职责链模式的目的仍然是为了解除耦合,从“封装变化”的角度出发,它封装了“职责行为的变化”,同时又利用链结构保证了消息的传递,此模式的优势在于它能够“智能”地根据条件在职责链中定位到合适的对象,并执行其职能。
    职责链模式的UML图如下:
                         

   责任链模式涉及到的角色如下所示:
   1、抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义出一个方法,以设定和返回对下家的引用。这个角色通常由一个抽象类或接口实现。
   2、具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
   下面,我们还是用代码来说明。
   程序如下图:

                        
      
   一、职责链模式的基本思路
  1、抽象处理者(Handler)角色:

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyChainResponsibility
{
    
abstract  class Handler
    {
        
//定义一个设置下一个处理者的接口
        protected Handler _successor;
        
public void SetSuccessor(Handler sucessor)
        {
            
this._successor = sucessor;
        }
        
//定义一个处理信息的接口
        public abstract void HandleRequest(int request);
    }
}

  2、具体处理者(ConcreteHandler)角色

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyChainResponsibility
ExpandedBlockStart.gifContractedBlock.gif
{
ContractedSubBlock.gifExpandedSubBlockStart.gif    
第一个处理者#region 第一个处理者
    
class ConcreteHandlerOne:Handler 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
public override void HandleRequest(int request)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if(request>=0 && request <10)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.WriteLine(
"{0} handled request{1}",this.GetType().Name,request);
            }

            
else if (_successor != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _successor.HandleRequest(request);
            }

        }


    }

    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
第二个处理者#region 第二个处理者
    
class ConcreteHandlerTwo : Handler
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
public override void HandleRequest(int request)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (request >= 10 && request < 40)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.WriteLine(
"{0} handled request{1}"this.GetType().Name, request);
            }

            
else if (_successor != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _successor.HandleRequest(request);
            }

        }


    }

    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
第三个处理者#region 第三个处理者
    
class ConcreteHandlerThree : Handler
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
public override void HandleRequest(int request)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (request >= 40 && request < 100)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.WriteLine(
"{0} handled request{1}"this.GetType().Name, request);
            }

            
else if (_successor != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _successor.HandleRequest(request);
            }

        }


    }

    
#endregion


}

  3、客户端应用

ContractedBlock.gif ExpandedBlockStart.gif Code
            #region 基本思路示例
            Console.WriteLine(
"-------基本思路示例----------");
            Handler h1 
= new ConcreteHandlerOne();
            Handler h2 
= new ConcreteHandlerTwo();
            Handler h3 
= new ConcreteHandlerThree();

            
//设置责任链
            h1.SetSuccessor(h2);
            h2.SetSuccessor(h3);

            
int[] requests = {2,5,21,22,18,26,89};
            
foreach (int request in requests)
            {
                
//责任处理
                h1.HandleRequest(request);
            }

            Console.ReadKey();
            
#endregion

   二、关于办公室发票报销的职责链处理模式
   办公室的发票,根据它们的金额大小分别由科长,处长,局长逐级负责审阅报批,职责链处理流程从科长到处长再到局长。代码如下
  1、抽象处理者(Handler)角色:ApproveHandler.

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyChainResponsibility
{
    
abstract  class ApproveHandler
    {
        
#region 职务属性
        
private string headship;
        
public string HeadShip
        {
            
get { return headship; }
            
set { headship = value; }
        }
        
#endregion

        
#region 构造函数
        
public ApproveHandler(string HeadShip)
        {
            
this.headship = HeadShip;
        }
        
#endregion

        
#region 设置后继者接口
        
protected ApproveHandler _successor;
        
public void SetSuccessor(ApproveHandler successor)
        {
            
this._successor = successor;
        }
        
#endregion

        
#region 处理职责接口
        
public abstract void HandleRequest(Receipt  request);
        
#endregion
    }
}

  2、具体处理者(ConcreteHandler)角色:ConcreteApproveHandlers

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyChainResponsibility
ExpandedBlockStart.gifContractedBlock.gif
{
ContractedSubBlock.gifExpandedSubBlockStart.gif    
科长#region 科长
    
class  KeZhang:ApproveHandler
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{

        
public KeZhang(string duty):base(duty)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{

        }


        
public override void HandleRequest(Receipt  request)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (request.Amount > 0 && request.Amount < 500)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.WriteLine(
"{0}负责审阅此帐单,帐单金额为: {1},帐单用途为: {2}",this.HeadShip,request.Amount,request.Purpose);
            }

            
else if (_successor!=null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _successor.HandleRequest(request);
            }

        }

    }

    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
处长#region 处长
    
class ChuZhang : ApproveHandler
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
public ChuZhang(string duty)
             : 
base(duty)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{

        }


        
public override void HandleRequest(Receipt  request)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (request.Amount > 500 && request.Amount < 1000)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.WriteLine(
"{0}负责审阅此帐单,帐单金额为: {1},帐单用途为: {2}"this.HeadShip, request.Amount, request.Purpose);
            }

            
else if (_successor != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _successor.HandleRequest(request);
            }

        }

    }

    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
局长#region 局长
    
class JuZhang : ApproveHandler
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
         
public JuZhang(string duty)
             : 
base(duty)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{

        }


        
public override void HandleRequest(Receipt  request)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (request.Amount > 1000)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.WriteLine(
"{0}负责审阅此帐单,帐单金额为: {1},帐单用途为: {2}"this.HeadShip, request.Amount, request.Purpose);
            }

            
else if (_successor != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _successor.HandleRequest(request);
            }

        }

    }

    
#endregion

}

  3、客户端应用
   Receipt发票类定义

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyChainResponsibility
{
    
#region 发票类
    
class Receipt
    {
        
private double _amount;
        
private string _purpose;

        
// 构造函数
        public Receipt( double amount, string purpose)
        {
            
this._amount = amount;
            
this._purpose = purpose;
        }

        
#region 金额
        
public double Amount
        {
            
get { return _amount; }
            
set { _amount = value; }
        }
        
#endregion

        
#region 用途
        
public string Purpose
        {
            
get { return _purpose; }
            
set { _purpose = value; }
        }
        
#endregion
    }
    
#endregion
}


   客户端应用

ContractedBlock.gifExpandedBlockStart.gifCode
          #region 办公室报销责任链
            Console.WriteLine(
"-------办公室报销责任链----------");
            KeZhang ke 
= new KeZhang("科长");
            ChuZhang chu 
= new ChuZhang("处长");
            JuZhang ju 
= new JuZhang("局长");

            Receipt r1 
= new Receipt(360"请客吃饭.");
            Receipt r2 
= new Receipt(760"处室活动开销.");
            Receipt r3 
= new Receipt(360"采购办公用品.");

            
//设置责任链
            ke.SetSuccessor(chu);
            chu.SetSuccessor(ju);

            
//责任处理
            ke.HandleRequest(r1);
            ke.HandleRequest(r2);
            ke.HandleRequest(r3);

            Console.ReadKey();
            
#endregion

总结

1、何时采用
  从代码角度来说,如果一个逻辑的处理由不同责任对象完成,客户端希望能自定义这个处理流程并且不希望直接和多个责任对象发生耦合的时候可以考虑责任链模式。
 从应用角度来说,如果对一个事情的处理存在一个流程,需要经历不同的责任点进行处理,并且这个流程比较复杂或只希望对外公开一个流程的入口点的话可以考虑责任链模式。其实,责任链模式还可以在构架的层次进行应用,比如.NET中的层次异常处理关系就可以看作是一种责任链模式。

 2、实现要点
 (1)有一个抽象责任角色,避免各责任类型之间发生耦合。
 (2)抽象责任角色中定义了后继责任角色,并对外提供一个方法供客户端配置。
 (3)各具体责任类型根据待处理对象的状态结合自己的责任范围来判断是否能处理对象,如果不能处理提交给上级责任人处理(也就是纯的责任模式,要么自己处理要么提交给别人)。当然,也可以在进行部分处理后再提交给上级处理(也就是不纯的责任链模式)。
 (4)需要在客户端链接各个责任对象,如果链接的不恰当,可能会导致部分对象不能被任何一个责任对象进行处理。

 3、注意事项
    责任链模式和状态模式的区别在于,前者注重责任的传递,并且责任链由客户端进行配置,后者注重对象状态的转换,这个转换过程对客户端是透明的。

前往:设计模式学习笔记清单
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值