1

I quite understand the basics of the Chain of Responsibility pattern. However, I would like to ask if it is possible to set the next receiver in the sequence dynamically.

The basic idea is that depending on the sequence of the approver, it will instantiate the next object.

Below is the example:

Abstract Base Class

public abstract class ApproverCategorizer
{
    protected ApproverCategorizer NextApprover { get; private set; }

    public ApproverCategorizer RegisterNextApprover(ApproverCategorizer nextApprover)
    {
        NextApprover = nextApprover;
        return nextApprover;
    }

    public abstract void ApproveAmount(TestEntity entity);

    protected bool IsLast(Queue<string> approverQueue)
    {
        return string.IsNullOrEmpty(approverQueue.Peek());
    }
}

Officer approver class

public class OfficerAApprover : ApproverCategorizer
{
    public override void ApproveAmount(TestEntity entity)
    {
        entity.ApproverQueue.Dequeue();

        if (entity.Amount <= 300)
        {
            entity.Status = "Approved";
            return;
        }

        if (!IsLast(entity.ApproverQueue) && string.IsNullOrWhiteSpace(entity.Status))
        {
            NextApprover.ApproveAmount(entity);
            return;
        }
        else
        {
            entity.Status = "Rejected";
        }

    }

}

Officer B Class

public class OfficerBApprover : ApproverCategorizer
{
    public override void ApproveAmount(TestEntity entity)
    {
        entity.ApproverQueue.Dequeue();

        if (entity.Amount <= 300)
        {
            entity.Status = "Approved";
            return;
        }

        if (!IsLast(entity.ApproverQueue) && string.IsNullOrWhiteSpace(entity.Status))
        {
            NextApprover.ApproveAmount(entity);
            return;
        }
        else
        {
            entity.Status = "Rejected";
        }

    }

}

Approver Chain Class

public class ApproverChain
{
    public static TestEntity Entity { get; set; }
    public static ApproverCategorizer Approver { get; set; }

    public ApproverChain()
    {
        List<string> approverList = Entity.ApproverList.Split(',').ToList();
        Queue<string> approverQueue = new Queue<string>();

        Approver = new StartApprover();
        // Note: The code below is working, but not the desired logic.
        //Approver.RegisterNextApprover(new OfficerAApprover()).RegisterNextApprover(new OfficerBApprover());

        // Note: This code below is not working, but this is the desired logic.
        foreach (string approver in approverList)
        {
            switch (approver)
            {
                case "OfficerA":
                    Approver.RegisterNextApprover(new OfficerAApprover());
                    break;
                case "OfficerB":
                    Approver.RegisterNextApprover(new OfficerBApprover());
                    break;
            }
            approverQueue.Enqueue(approver);

        }

        Entity.ApproverQueue = approverQueue;

    }

    public string StartProcess()
    {
        Approver.ApproveAmount(Entity);
        return Entity.Status;
    }
}

Business Class

public string ProcessApproval()
{
  TestEntity entity = new TestEntity
  {
     Amount = 500,
     ApproverList = "OfficerB,OfficerA"
  };

  ApproverChain.Entity = entity;
  ApproverChain chain = new ApproverChain();
  var result = chain.StartProcess();

  return result;
}

This means that the OfficerB class will process first. If it fails, it will go to OfficerA class.

Is there a way to tweak it to the desired logic as mentioned? If so, how is it done?

4

1 回答 1

3

如果我理解正确,您需要通过运行时值(在这种情况下为字符串)配置您的批准者。

只需对您的代码进行很少的更改,这是可能的。这是所需的修改。

public ApproverChain()
{
    List<string> approverList = Entity.ApproverList.Split(',').ToList();
    Queue<string> approverQueue = new Queue<string>();

    Approver = new StartApprover();

    ApproverCategorizer currentApprover = Approver;
    foreach (string approver in approverList)
    {
        switch (approver)
        {
            case "OfficerA":
                currentApprover = currentApprover.RegisterNextApprover(new OfficerAApprover());
                break;
            case "OfficerB":
                currentApprover = currentApprover.RegisterNextApprover(new OfficerBApprover());
                break;
        }
        approverQueue.Enqueue(approver);
    }

    Entity.ApproverQueue = approverQueue;
}

上面的代码可以正常工作。但对我来说,ApproverQueue看起来很可疑。

您似乎拥有ApproverQueue财产只是为了确定当前批准者是否是链中的最后一个批准者。您可以通过简单地检查NextApprovernull 并完全摆脱它来找到它approverQueue

然后你的代码变成

public class ApproverChain
{
    public static TestEntity Entity { get; set; }
    public static ApproverCategorizer Approver { get; set; }

    public ApproverChain()
    {
        Approver = new StartApprover();

        List<string> approverList = Entity.ApproverList.Split(',').ToList();

        ApproverCategorizer currentApprover = Approver;
        foreach (string approver in approverList)
        {
            switch (approver)
            {
                case "OfficerA":
                    currentApprover = currentApprover.RegisterNextApprover(new OfficerAApprover());
                    break;
                case "OfficerB":
                    currentApprover = currentApprover.RegisterNextApprover(new OfficerBApprover());
                    break;
            }
        }
    }

    public string StartProcess()
    {
        Approver.ApproveAmount(Entity);
        return Entity.Status;
    }
}

public abstract class ApproverCategorizer
{
    protected ApproverCategorizer NextApprover { get; private set; }

    public ApproverCategorizer RegisterNextApprover(ApproverCategorizer nextApprover)
    {
        NextApprover = nextApprover;
        return nextApprover;
    }

    public abstract void ApproveAmount(TestEntity entity);

    protected bool IsLast()
    {
        return NextApprover == null;
    }
}

public class OfficerAApprover : ApproverCategorizer
{
    public override void ApproveAmount(TestEntity entity)
    {
        if (entity.Amount <= 300)
        {
            entity.Status = "Approved";
            return;
        }

        if (!IsLast() && string.IsNullOrWhiteSpace(entity.Status))
        {
            NextApprover.ApproveAmount(entity);
            return;
        }
        else
        {
            entity.Status = "Rejected";
        }
    }
}

你的TestEntity班级将没有ApproverQueue财产。

于 2015-03-17T07:11:53.213 回答