120 likes | 293 Views
Behavioral Patterns. Chapter 5 – Page 128. Behavioral Pattern: Chain of Responsibility. Chapter 5 – Page 129. On occasion, a system might have more than one mechanism for dealing with requests.
E N D
Behavioral Patterns Chapter 5 – Page 128
Behavioral Pattern: Chain of Responsibility Chapter 5 – Page 129 On occasion, a system might have more than one mechanism for dealing with requests. The Chain of Responsibility pattern sets up the automatic selection of the appropriate mechanism for handling a particular request. By passing the request along the chain until some mechanism handles it, loose coupling is promoted between the mechanisms’ classes .
The Chain of Responsibility Pattern Chapter 5 – Page 130 The Client initiates a request to a ConcreteHandler on the chain. The Handler defines an interface for handling the request and (optionally) implements the successor link. Each ConcreteHandler handles the requests for which it is responsible and can access its successor. If a ConcreteHandler can handle a request, it does so; otherwise it forwards the request to its successor.
Non-Software Example: ATM Withdrawal Chapter 5 – Page 131 The base ATM class calls the handlers in succession until the requested withdrawal amount is achieved. Each handler repeatedly subtracts its designated amount from the sum requested until that sum exceeds the designated amount. The handler indicates to the ATM whether or not the next handler needs to be called.
Software Example: Calendar Chapter 5 – Page 132 When requesting the number of days in a specified month, the 31DayHandler begins the chain, followed by the 30DayHandler, then the FebruaryHandler, and finally the MistakeHandler.
Calendar Code in C++ Chapter 5 – Page 133 #include <iostream> #include <string> using namespace std; classMonthHandler { public: MonthHandler() { successorMonthHandler = 0; } voidsetSuccessor(MonthHandler *smh) { successorMonthHandler = smh; } void add(MonthHandler *mh) { if (successorMonthHandler) successorMonthHandler->add(mh); else successorMonthHandler = mh; } // The "chain" method in the base class always delegates to the next object virtual intnumberOfDays(string monthName, int year) { returnsuccessorMonthHandler->numberOfDays(monthName, year); } protected: MonthHandler *successorMonthHandler; };
Chapter 5 – Page 134 classThirtyOneDayHandler: publicMonthHandler { public: intnumberOfDays(string monthName, int year) { if ( (monthName == "January") || (monthName == "March") || (monthName == "May") || (monthName == "July") || (monthName == "August") || (monthName == "October") || (monthName == "December") ) return 31; else returnsuccessorMonthHandler->numberOfDays(monthName, year); } }; classThirtyDayHandler: publicMonthHandler { public: intnumberOfDays(string monthName, int year) { if ( (monthName == "April") || (monthName == "June") || (monthName == "September") || (monthName == "November") ) return 30; else returnsuccessorMonthHandler->numberOfDays(monthName, year); } };
Chapter 5 – Page 135 classFebruaryHandler: publicMonthHandler { public: intnumberOfDays(string monthName, int year) { if (monthName == "February") if (year % 4 == 0) return 29; else return 28; else returnsuccessorMonthHandler->numberOfDays(monthName, year); } }; classMistakeHandler: publicMonthHandler { public: intnumberOfDays(string monthName, int year) { return 0; } };
Chapter 5 – Page 136 void main() { string monthName; int year; intnbrOfDays; ThirtyOneDayHandler handler31; ThirtyDayHandler handler30; FebruaryHandlerhandlerFeb; MistakeHandlerhandlerMistake; handler31.add(&handler30); handler31.add(&handlerFeb); handler31.add(&handlerMistake); handlerMistake.setSuccessor(&handler31); cout << "How many days in any given month?" << endl; cout << endl << "Let's find out... " << endl << endl; cout << "Enter a year (use 0 to quit): "; cin >> year; while (year != 0) { cout << "Enter the name of a month: "; cin >> monthName; nbrOfDays = handler31.numberOfDays(monthName, year); if (nbrOfDays != 0) cout << monthName << ' ' << year << " has " << nbrOfDays << " days!" << endl << endl; else cout << "Sorry, but there IS no month called " << monthName << "!!!" << endl << endl; cout << "Want another? Enter a year (use 0 to quit): "; cin >> year; } }
Chain of Responsibility Pattern Advantages Chapter 5 – Page 138 • Chain of Responsibility 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. • The Chain of Responsibility pattern can be used to deal with long if-then-else statements. A much more descriptive path can be made by coding it into a framework of successive objects that keep a reference to one another in the path, so that a logical path is built by the objects themselves. • The Chain of Responsibility pattern is often used in conjunction with the Composite structural pattern, with a component’s parent acting as its successor.