- Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
- The pattern chains the receiving objects together and then passes any request messages from object to object until it reaches an object capable of handling the message.
- The number and type of handler objects isn’t known to the client, they can be configured dynamically.
- This pattern simplifies object interconnections. Instead of senders and receivers maintaining references to all candidate receivers, each sender keeps a single reference to the head of the chain and each receiver keeps a single reference to its immediate successor in the chain.
#include <iostream>
using namespace std;
// STATES
enum ErrorStates
{ ANALYZE=0,
FIX,
VERIFY,
CLOSE
};
// Command Class
class ErrorReport
{
private:
ErrorStates state;
public:
ErrorReport(ErrorStates state)
{
this->state = state;
}
ErrorStates GetState()
{
return state;
}
void SetState(ErrorStates state)
{
this->state = state;
}
};
// General base class for all processing objects
class Error
{
protected:
ErrorStates state;
Error* successor;
public:
Error(ErrorStates aState)
{
state = aState;
}
void SetSuccessor (Error* error)
{
this->successor = error;
}
virtual void ProcessError(ErrorReport& report) = 0;
};
// Processing object class 1 for state ANALYZE
class AnalyzeError : public Error
{
public:
AnalyzeError() : Error(ANALYZE) {};
void ProcessError(ErrorReport& report)
{
if ( report.GetState() == ANALYZE )
{
cout << "AnalyzeError::Handled the command to analyze the error ..." << endl;
}
else
{
cout << "AnalyzeError::Passing to my successor ..." << endl;
successor->ProcessError(report);
}
}
};
// Processing object class 2 for state FIX
class FixError : public Error
{
public:
FixError() : Error(FIX) {};
void ProcessError(ErrorReport& report)
{
if ( report.GetState() == FIX )
{
cout << "FixError::Handled the command to fix the error ..." << endl;
}
else
{
cout << "FixError::Passing to my successor ..." << endl;
successor->ProcessError(report);
}
}
};
// Processing object class 3 for state VERIFY
class VerifyError : public Error
{
public:
VerifyError() : Error(VERIFY) {};
void ProcessError(ErrorReport& report)
{
if ( report.GetState() == VERIFY )
{
cout << "VerifyError::Handled the command to verify the error ..." << endl;
}
else
{
cout << "VerifyError::Passing to my successor ..." << endl;
successor->ProcessError(report);
}
}
};
// Processing object class 4 for state CLOSE
class CloseError : public Error
{
public:
CloseError() : Error(CLOSE) {};
void ProcessError(ErrorReport& report)
{
if ( report.GetState() == CLOSE )
{
cout << "CloseError::Handled the command to close the error ..." << endl;
}
else
{
cout << "VerifyError::No successor ... ignore" << endl;
cout << "No action required ..." << endl;
}
}
};
int main()
{
// Create instances for processing objects
AnalyzeError* analyzeError = new AnalyzeError();
FixError* fixError = new FixError();
VerifyError* verifyError = new VerifyError();
CloseError* closeError = new CloseError();
// Create the chain of responsibility
analyzeError->SetSuccessor(fixError);
fixError->SetSuccessor(verifyError);
verifyError->SetSuccessor(closeError);
// Issue command 1
cout << "--------------- o/p for command 1 ----------------" << endl;
ErrorReport* errorReport1 = new ErrorReport(ANALYZE);
analyzeError->ProcessError(*errorReport1);
// Issue command 2
cout << "--------------- o/p for command 2 ----------------" << endl;
ErrorReport* errorReport2 = new ErrorReport(CLOSE);
analyzeError->ProcessError(*errorReport2);
// Cleanup
delete errorReport2;
delete errorReport1;
delete closeError;
delete verifyError;
delete fixError;
delete analyzeError;
}
Advantages:
The sender is free from knowing which receiver handles a request.
Sender and receiver have no knowledge of each other, hence are loosely coupled.
You get added flexibility in distributing responsibilities among objects. Responsibilities can be added or changed for handling requests by changing the chain at runtime.
Disadvantage:
Since a request has no explicit receiver, there’s no guarantee it will be handled – the request may fall off the chain without ever being handled ( usually happens in chains that are not configured correctly)
When to use this pattern:
- More than one object may handle a request, and the handler isn’t known. The handler should be ascertained automatically.
- You want to issue a request to one of several objects without specifying the receiver explicitly.
- The set of object that can handle a request should be specified dynamically.
- You want to distribute work between different objects.