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?