职责链模式

一、概念

在系统中如果存在多个对象可以处理同一请求,则可以通过职责链模式将这些处理请求的对象连成一条链,让请求沿着该链进行传递。如果链上的对象可以处理该请求则进行处理,否则将请求转发给下家进行处理。

定义:避免将一个请求的发送者与接收者耦合在一起。让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并沿着这条链传递请求,直到有一个对象能够处理它为止。

二、模式结构

  • Handler(抽象处理者):它定义一个处理请求的接口,包含了抽象处理方法和后继连接。

  • Concrete Handler(具体处理者):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。

  • Client(客户端角色):创建处理链,并向链头的具体处理者对象提交请求。

    image-20240708232919630

三、具体实现

设计一个系统关于采购审批子系统,根据采购金额的不同由不同层次的主管人员进行审批,其中主任可以审批5万元以下,副董事长可以审批5-10万,董事长可以审批10-50万,超过50万需要董事会开会决定。

  • PurchaseRequest(请求类):采购单类
public class PurchaseRequest
{
    private double _amount;
    private int _number;
    private string _purpose;

    public PurchaseRequest(double amount, int number, string purpose)
    {
        _amount = amount;
        _number = number;
        _purpose = purpose;
    }
    public void SetPurchase(double amount, int number)
    {
        _amount = amount;
        _number = number;
    }

    public double GetTotalPrice()
    {
        return _number * _amount;
    }
    public string GetPurchase()
    {
        return _purpose;
    }
}
  • Approver(抽象处理类):审批者类
public abstract class Approver
{
    protected Approver successor;   //后继对象
    protected string name;          //审批者姓名

    public Approver(string name)
    {
        this.name = name;
    }

    public void SetSuccessor(Approver successor)
    {
        this.successor = successor;
    }

    public abstract void ProcessRquest(PurchaseRequest purchase);
}
  • Concrete Approver(具体处理类):具体审批类
public class Director : Approver
{
    public Director(string name) : base(name)
    {
        this.name = name;
    }

    public override void ProcessRquest(PurchaseRequest purchase)
    {
        if (purchase.GetTotalPrice() < 50000)
        {
            Console.WriteLine($"主任:{name} 审批采购单: {purchase.GetPurchase()} 金额:{purchase.GetTotalPrice()}");
        }
        else
        {
            this.successor.ProcessRquest(purchase);
        }
    }
}

public class VicePresident : Approver
{
    public VicePresident(string name) : base(name)
    {
        this.name = name;
    }

    public override void ProcessRquest(PurchaseRequest purchase)
    {
        if (purchase.GetTotalPrice() < 100000)
        {
            Console.WriteLine($"副董事长:{name} 审批采购单: {purchase.GetPurchase()} 金额:{purchase.GetTotalPrice()}");
        }
        else
        {
            this.successor.ProcessRquest(purchase);
        }
    }
}

public class President : Approver
{
    public President(string name) : base(name)
    {
        this.name = name;
    }

    public override void ProcessRquest(PurchaseRequest purchase)
    {
        if (purchase.GetTotalPrice() < 500000)
        {
            Console.WriteLine($"董事长:{name} 审批采购单: {purchase.GetPurchase()} 金额:{purchase.GetTotalPrice()}");
        }
        else
        {
            this.successor.ProcessRquest(purchase);
        }
    }
}

public class Congress : Approver
{
    public Congress(string name) : base(name)
    {
        this.name = name;
    }

    public override void ProcessRquest(PurchaseRequest purchase)
    {
        Console.WriteLine($"召开董事会 审批采购单: {purchase.GetPurchase()} 金额:{purchase.GetTotalPrice()}");
    }
}
  • Client:客户端类
public class Client
{
    public void Main(string[] args)
    {
        Approver liming, jianguo, lihua, meet;
        liming = new Director("李明");
        jianguo = new VicePresident("建国");
        lihua = new President("李华");
        meet = new Congress("董事会");

        liming.SetSuccessor(jianguo);
        jianguo.SetSuccessor(lihua);
        lihua.SetSuccessor(meet);

        PurchaseRequest purchase = new PurchaseRequest(45000, 1, "办公桌");
        liming.ProcessRquest(purchase);

        PurchaseRequest purchase1 = new PurchaseRequest(60000, 1, "电梯");
        liming.ProcessRquest(purchase1);

        PurchaseRequest purchase2 = new PurchaseRequest(150000, 1, "空调");
        liming.ProcessRquest(purchase2);

        PurchaseRequest purchase3 = new PurchaseRequest(510000, 1, "办公室");
        liming.ProcessRquest(purchase3);

        /*
         * 主任:李明 审批采购单: 办公桌 金额:45000
         * 副董事长:建国 审批采购单: 电梯 金额:60000
         * 董事长:李华 审批采购单: 空调 金额:150000
         * 召开董事会 审批采购单: 办公室 金额:510000
         */
    }
}

四、优缺点

  • 优点:
    1. 降低耦合度:请求发送者不需要知道具体的处理者是谁,也不需要关心请求是如何被处理的,降低了发送者和处理者之间的耦合度。
    2. 可扩展性:可以动态地添加或者修改处理链,增加新的处理者或者调整处理顺序,而无需要修改已有代码。
  • 缺点:
    1. 请求可能未被处理:如果责任链中没有正确配置明确的接收者或者最后一个接受者没有处理请求,则请求会被漏掉,一直没法处理。
    2. 性能影响:如果处理链过长,则系统性能会受到一定影响。

五、适用环境

  1. 有多个对象可以处理同一请求,具体哪个对象处理该请求待运行时在确定。
  2. 动态指定一组对象处理请求,动态创建职责链来处理请求,还可以改变链中处理者之间的次序。