Command Pattern When Actions Speak Louder Than Words
Programmable Remote Example in book On/off for seven devices Single “Undo” button referring to the last button pushed Can control a wide variety of devices from lights to TVs to other appliances Difference devices support different operations Many are on/off setTemperature(), circulate(), selectChannel(), etc. Example in book On/off for seven devices Single “Undo” button referring to the last button pushed Can control a wide variety of devices from lights to TVs to other appliances Difference devices support different operations Many are on/off setTemperature(), circulate(), selectChannel(), etc.
Goals of a Good design For This Situation Separate the remote’s ability to execute a command from the variety of operations and devices that can be supported. What varies? Devices and operations What Stays the same? The structure of the remote control Separate the remote’s ability to execute a command from the variety of operations and devices that can be supported. What varies? Devices and operations What Stays the same? The structure of the remote control
Four Parts of our Design The actions that we want each button to cause (Command) Someone to set up those actions (Client) The remote control to execute the actions (Invoker) The device affected by the action (Receiver) The actions that we want each button to cause (Command) Someone to set up those actions (Client) The remote control to execute the actions (Invoker) The device affected by the action (Receiver)
Command Pattern ClientInvoker setCommand() > Command execute() undo() Receiver action() ConcreteCommand execute() undo() public void execute() { receiver.action() }
Command There are a variety of commands, but we want the remote to treat them all the same Need Command interface (with an execute() method) Need Concrete Commands for each operation we will support Concrete Commands pair the operation with the device it will affect - “light On” paired with a specific light in the house. There are a variety of commands, but we want the remote to treat them all the same Need Command interface (with an execute() method) Need Concrete Commands for each operation we will support Concrete Commands pair the operation with the device it will affect - “light On” paired with a specific light in the house.
Receiver The object the command should affect
Invoker Executes the Commands Possibly at a later time Executes the Commands Possibly at a later time
Let’s Look at the Code Command.SimpleRemote Command.Remote Find Devices Concrete Commands Remote Control Client Command.SimpleRemote Command.Remote Find Devices Concrete Commands Remote Control Client
What about that Undo Button? Add undo() to the Command interface Each ConcreteCommand must know how to undo the action it executed Make Remote remember the last command executed and call it’s undo method for the undo button. Add undo() to the Command interface Each ConcreteCommand must know how to undo the action it executed Make Remote remember the last command executed and call it’s undo method for the undo button.
Let’s Look at the code How does remote remember previously executed command? Undo for Lights - simple (does light off need the hardcoded previous value?) Dimmer - ask device for state before execution Ceiling fan - see any duplication? How could we eliminate it? How does remote remember previously executed command? Undo for Lights - simple (does light off need the hardcoded previous value?) Dimmer - ask device for state before execution Ceiling fan - see any duplication? How could we eliminate it?
Macro Commands Can make a Concrete Command (subclass of Command) that contains a list of commands Commands can be given at construction, or set up via method calls Execute method calls the execute method on each of the commands in the list How could we use this to give a good progress indicator? Can make a Concrete Command (subclass of Command) that contains a list of commands Commands can be given at construction, or set up via method calls Execute method calls the execute method on each of the commands in the list How could we use this to give a good progress indicator?
Other uses of command Queuing requests Can allocate commands to various threads for processing to load balance between threads/processors Logging requests (audit trail) Just have to save the command objects as they execute. If something goes wrong, we can read the log and re-create the sequence of commands (so no data is lost). Can also back out changes that cause troubles Queuing requests Can allocate commands to various threads for processing to load balance between threads/processors Logging requests (audit trail) Just have to save the command objects as they execute. If something goes wrong, we can read the log and re-create the sequence of commands (so no data is lost). Can also back out changes that cause troubles
Starting Lab TODAY!