- Back to Home »
- Chain of Responsibility
Chain of Responsibility:
Scenario: Design the software for a system that approves purchasing requests. The approval authority depends on the dollar amount of the purchase. The approval authority for a given dollar amount could change at any time and the system should be flexible enough to handle this situation.
Solution: PurchaseRequest objects forward the approval request to a PurchaseApproval
object. Depending on the dollar amount, the PurchaseApproval object may approve
the request or forward it on to the next approving authority in the chain. The
approval authority at any level in the chain can be easily modified without affecting
the original PurchaseRequest object. => Chain of Responsibility pattern.
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.
Use Chain of Responsibility:
Ø When more than one object may handle a request and the actual
handler is not know in advance
Ø When requests follow a “handle or forward” model - that is, some
requests can be handled where they are generated while others must be forwarded
to another object to be handled
Ø Reduced coupling between the sender of a request and the receiver –
the sender and receiver have no explicit knowledge of each other
Ø The chain of handlers can be modified dynamically
DisAdvantages:
Receipt is not guaranteed - a request
could fall off the end of the chain without being handled
Structure:
The derived classes know how to satisfy Client requests. If the “current” object is not available or sufficient, then it delegates to the base class, which delegates to the “next” object, and the circle of life continues.
Multiple handlers
could contribute to the handling of each request. The request can be passed
down the entire length of the chain, with the last link being careful not to
delegate to a “null next”.
Code Flow:
- The base class maintains a
“next” pointer.
- Each derived class implements its
contribution for handling the request.
- If the request needs to be “passed
on”, then the derived class “calls back” to the base class, which
delegates to the “next” pointer.
- The client (or some third party)
creates and links the chain (which may include a link from the last node
to the root node).
- The client “launches and leaves”
each request with the root of the chain.
- Recursive delegation produces the
illusion of magic.
|
#include <iostream> using namespace std;
enum ErrorStates { ANALYZE=0,FIX,VERIFY,CLOSE };
class ErrorReport {
private: ErrorStates state;
public: ErrorReport(ErrorStates state) { this->state = state; } ErrorStates GetState() { return state; } void setState(ErrorStates state) { this->state= state; } };
class Error { protected: ErrorStates state; Error *next;
public: //Constructor Error(ErrorStates astate){state = astate;}
//set the successor void setnext(Error *n) { this->next = n; }
//pure virtual function
to be implemented by concrete classes virtual void ProcessError(ErrorReport &Err) =
0; };
class FixError : public Error {
public: FixError() : Error(FIX) {} void ProcessError(ErrorReport &Err) { if(Err.GetState() == FIX) cout << "Error to be fixed "<< endl; else { cout <<"error not fixed"<< endl; |
||
|
next->ProcessError(Err); } } }; class AnalyzeError : public Error { public: AnalyzeError() : Error(ANALYZE){} void ProcessError(ErrorReport &Err) { if(Err.GetState() == ANALYZE) cout << "Error to be analyzed "<< endl; else { cout <<"error not handled in analysis"<< endl; next->ProcessError(Err); } } };
class VerifyError : public Error { public: VerifyError() : Error(VERIFY){} void ProcessError(ErrorReport &Err) { if(Err.GetState() == VERIFY) cout << "Error to be verified "<< endl; else { cout <<"error not handled in verify"<< endl; next->ProcessError(Err); } } }; class CloseError : public Error { public: CloseError() : Error(CLOSE){} void ProcessError(ErrorReport &Err) { if(Err.GetState() == CLOSE) cout << "Error to be closed "<< endl; else { cout <<"error not handled in close"<< endl; next->ProcessError(Err); } } };
int main() { AnalyzeError *AE = new AnalyzeError(); FixError *FE = new FixError(); |
|
|
CloseError *CE= new CloseError(); VerifyError *VE = new VerifyError();
AE->setnext(FE); FE->setnext(VE); VE->setnext(CE);
ErrorReport *ERA = new ErrorReport(ANALYZE); AE->ProcessError(*ERA);
ErrorReport *ERC = new ErrorReport(CLOSE); AE->ProcessError(*ERC);
delete AE; delete FE; delete CE; delete VE; delete ERA; delete ERC;
cout << "Stack
Implementation" <<
endl; // prints Stack Implementation return 0; } |
|