Presentation is loading. Please wait.

Presentation is loading. Please wait.

Behavioral Pattern: Command C h a p t e r 5 – P a g e 139 There are times when the need arises to issue a request to an object without knowing anything.

Similar presentations


Presentation on theme: "Behavioral Pattern: Command C h a p t e r 5 – P a g e 139 There are times when the need arises to issue a request to an object without knowing anything."— Presentation transcript:

1

2 Behavioral Pattern: Command C h a p t e r 5 – P a g e 139 There are times when the need arises to issue a request to an object without knowing anything about the operation being requested or the object receiving the request. The Command Pattern encapsulates the request as an object, which allows clients to be parameterized with different requests, requests to be logged or queued, and undoable operations to be supported.

3 The Command Pattern C h a p t e r 5 – P a g e 140 The Command declares an interface for executing an operation. The ConcreteCommand defines a binding between a Receiver object and an action, implementing Execute by invoking the corresponding operation on the Receiver. The Client creates a ConcreteCommand object and sets its Receiver. The Invoker asks the Command to carry out the request. The Receiver knows how to perform the operations associated with carrying out the request.

4 C h a p t e r 5 – P a g e 141 Non-Software Example: Diner The Waitress (invoker) generates an Order (concrete command) based upon what the Customer (client) selects from the menu, placing the order on a Check (command). The Order is then queued for the Cook (receiver) and, after being executed, the Order is delivered to the Customer. Note that the pad of “checks” used by each waitress is not dependent on the menu, so they can support commands to cook many different items.

5 C h a p t e r 5 – P a g e 142 Software Example: Integer Conversion This C++ code will convert an integer into binary, octal, or hexadecimal, but its design is rather rigid. int num; char ch; char tryAgain = 'y'; string output; do { cout << "Enter an integer value: "; cin >> num; cout << "Enter a conversion type " << " (b=binary, o=octal, h-hexadecimal): "; cin >> ch; switch( toupper(x) ) { case 'O': { output = to_oct(num); break; } case 'H': { output = to_hex(num); break; } case 'B': { output = to_bin(num); break; } default: { output = "invalid"; } } cout << "Result: " << output << endl << endl; cout << "Try again? (Y or N) "; cin >> tryAgain; } while ( (tryAgain == 'Y') || (tryAgain == 'y') ); Every time the operations change, the switch block needs to be modified. At the moment, operations are just functions which exist completely independently of each another, even though they're all in fact fairly similar, and selection is solely based on different character values. (These character values acting like runtime identifiers for the operations.) A better solution would build in some kind of relationship between all the operations, and tag each one with their character value identifier.

6 C h a p t e r 5 – P a g e 143 Integer Conversion With The Command Pattern By separating the conversion command from the object that performs it (the convertor), the total amount of code will undoubtedly increase, but the revised design breaks bigger problems down into sub-problems, producing small, reusable modules in the process.

7 C h a p t e r 5 – P a g e 144 Command-Based Integer Conversion Code in C++ #include #include // Enables the determination of bit lengths #include // Enables the creation/loading of string-streams #include // Enables the mapping of dictionary pairs using namespace std; class converter { public: virtual std::string convert(int) = 0; virtual ~converter() {} }; class hex_converter : public converter { public: std::string convert(int i) { std::stringstream ss; ss << std::hex << i; return ss.str(); } };

8 C h a p t e r 5 – P a g e 145 class oct_converter : public converter { public: std::string convert(int i) { std::stringstream ss; ss << std::oct << i; return ss.str(); } }; class bin_converter : public converter { public: std::string convert(int i) { std::bitset bits(i); std::stringstream ss; ss << bits; return ss.str(); } };

9 C h a p t e r 5 – P a g e 146 class dictionary { public: // The dictionary is loaded with the three character/converter pairs dictionary() { dict.insert( std::make_pair( 'B', new bin_converter ) ); dict.insert( std::make_pair( 'O', new oct_converter ) ); dict.insert( std::make_pair( 'H', new hex_converter ) ); } converter* lookup(char x) { std::map ::const_iterator iter; iter = dict.find( toupper(x) ); if ( iter != dict.end() ) return iter->second; else return NULL; } ~dictionary() { while( dict.begin() != dict.end() ) { delete dict.begin()->second; dict.erase( dict.begin() ); } private: // The STL library enables mapping between objects // between two types. In this case, the three user-entered // characters have corresponding converters, and this // mapping is used to create a dictionary between them. std::map dict; };

10 C h a p t e r 5 – P a g e 147 void main() { int num; char ch; char tryAgain = 'y'; string output; dictionary dict; do { cout << "Enter an integer value: "; cin >> num; cout << "Enter a conversion type (b=binary, o=octal, h-hexadecimal): "; cin >> ch; converter* con = dict.lookup( ch ); if ( con != NULL ) output = con->convert( num ); else output = "Invalid"; cout << "Result: " << output << endl << endl; cout << "Try again? (Y or N) "; cin >> tryAgain; } while ( (tryAgain == 'Y') || (tryAgain == 'y') ); }

11 Command Pattern Advantages C h a p t e r 5 – P a g e 148 The object that creates a command (the Client) is not the same object that executes it (the Invoker). This separation provides flexibility in the timing and sequencing of commands. Materializing commands as objects means they can be passed, staged, shared, loaded in a table, and otherwise instrumented or manipulated like any other object. Command objects can be thought of as "tokens" that are created by one entity that knows what needs to be done, and passed to another entity that has the resources for doing it. Another of the main reasons for using the Command Pattern is that it provides a convenient way to store and execute an Undo function. Each command object can remember what it just did and restore that state when requested to do so if the computational and memory requirements are not too overwhelming.


Download ppt "Behavioral Pattern: Command C h a p t e r 5 – P a g e 139 There are times when the need arises to issue a request to an object without knowing anything."

Similar presentations


Ads by Google