Design Patterns: Elements of Reusable Object-Oriented Software 270 class OpenCommand : public Command {
public:
OpenCommand(Application*);
virtual void Execute();
protected:
virtual const char* AskUser();
private:
Application* _application;
char* _response;
};
OpenCommand::OpenCommand (Application* a) {
_application = a;
}
void OpenCommand::Execute () {
const char* name = AskUser();
if (name != 0) {
Document* document = new Document(name);
_application->Add(document);
document->Open();
}
}
A PasteCommand must be passed a Document object asits receiver. The receiver is
given as a parameter to PasteCommand'sconstructor.
class PasteCommand : public Command {
public:
PasteCommand(Document*);
virtual void Execute();
private:
Document* _document;
};
PasteCommand::PasteCommand (Document* doc) { _document = doc; } void
PasteCommand::Execute () { _document->Paste(); }
For simple commands that aren't undoable and don't require arguments,we can use
a class template to parameterize the command's receiver.We'll define a template
subclass SimpleCommand for suchcommands. SimpleCommand is parameterized by
theReceiver type and maintains a binding between a receiver objectand an action
stored as a pointer to a member function.
Design Patterns: Elements of Reusable Object-Oriented Software 271 template class SimpleCommand : public Command {
public:
typedef void (Receiver::* Action)();
SimpleCommand(Receiver* r, Action a) :
_receiver(r), _action(a) { }
virtual void Execute();
private:
Action _action;
Receiver* _receiver;
};
The constructor stores the receiver and the action in the correspondinginstance
variables. Execute simply applies the action to thereceiver.
template void SimpleCommand<Receiver>::Execute () { (_receiver->*_action)(); }
To create a command that calls Actionon an instance of class MyClass, a client
simply writes
MyClass* receiver = new MyClass;
// ...
Command* aCommand =
new SimpleCommand(receiver, &MyClass::Action);
// ...
aCommand->Execute();
Keep in mind that this solution only works for simple commands. More complex
commands that keep track of not only their receivers but also arguments and/or
undo state require a Command subclass.
A MacroCommand manages a sequence of subcommands and providesoperations for adding
and removing subcommands. No explicit receiveris required, because the subcommands
already define their receiver.
class MacroCommand : public Command {
public:
MacroCommand();
virtual ~MacroCommand();
virtual void Add(Command*);
virtual void Remove(Command*);
virtual void Execute();
private:
List* _cmds;