While implementing the Chain of Responsibility pattern, i came across a dilemma on how to pass data between objects in the chain. The datatypes passed between object in the chain can differ for each object. As a temporary fix I had created a Static class containing a stack where each object in the chain can push the results to the stack while the next object in the chain could pop the results from the stack. Here is a sample code on what I had implemented.
public interface IHandler
{
IHandler Successor {get; set; }
void Process();
}
//Temporary Data Container class to store objects\data
public static class StackManager
{
public static Stack DataStack = new Stack();
}
//This class doesn't require any input to operate
public class OpsA : IHandler
{
public IHandler Successor {get; set; }
public void Process()
{
//Do some processing, store the result into Stack
var ProcessedData = DoSomeOperation();
StackManager.DataStack.Push(ProcessedData);
if(Successor != null) Successor();
}
}
//This class require input data to operate upon
public class OpsB : IHandler
{
public IHandler Successor {get; set; }
public void Process()
{
//Retrieve the results from the previous Operation
var InputData = StackManager.DataStack.Pop();
//Do some processing, store the result into Stack
var NewProcessedData = DoMoreProcessing(InputData);
StackManager.DataStack.Push(NewProcessedData);
if(Successor != null) Successor();
}
}
public class ChainOfResponsibilityPattern
{
public void Process()
{
IHandler ProcessA = new OpsA();
IHandler ProcessB = new OpsB();
ProcessA.Successor = ProcessB;
ProcessA.Process();
}
}
Please help me to find a better approach to pass data between handlers in the chain.
For example, an ATM uses the Chain of Responsibility design pattern in money giving process. In other words, we can say that normally each receiver contains reference of another receiver. If one object cannot handle the request then it passes the same to the next receiver and so on.
Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.
Consequences. Chain of Responsibility has the following benefits and liabilities: Reduced coupling. The pattern frees an object from knowing which other object handles a request.
The Chain of Responsibility (CoR) law ensures everyone who works with heavy vehicles – from the business that employs a driver to the place where goods are delivered – is accountable for safety.
When you have a Chain of Responsibility, this typically involves a single context therefore a good approach is to pass on a Context
object.
One interesting thing I would note is around the mutability of the context.
You can have a mutable context and then you would instantiate the context object, pass it to ProcessorA
. ProcessorA
may modify it and set its own data, then pass it on to ProcessorB
. Then ProcessorB
modifies it some more and finally the caller may read the context.
If you want to have more data safety and encapsulate the behavior of each Processor
as a input-to-output blackbox, you may opt for an immutable context object. ProcessorA
may receive an empty context object, then construct one for ProcessorB
and return ProcessorB
's output.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With