Command
Command
Command
05/09/2024 1
Agenda
Command Pattern
Head First Example (Remote Control)
Lab
History of Undo Operations
Simple Logging
Complex Logging
Case Study: Command Management
Distributed Command Pattern
05/09/2024 2
Remote Control
Given remote control with seven programmable slots.
05/09/2024 3
First Thoughts
We know that there are seven programmable slots for
different devices…so each device may possibly adhere
to some common interface.
05/09/2024 4
What Varies? What stays the same?
What Varies
The actual device assigned to a slot
The instruction for “On” on a specific device
The instruction for “Off” on a specific device
05/09/2024 5
The Vendor Classes (pg 194)
Vendor classes have been provided to us via a CD.
Ceiling Light
TV
Hottub
05/09/2024 6
One possible solution…
if (slot1 == Light) Problems:
light.on();
The Remote needs to be
Else if (slot1 == Hottub) { aware of all the details about
hottub.prepareJets(); turning a device on (or off).
hottub.jetsOn();
If device On/Off mechanism
changes, the Remote code
} Else if (slot1 == TV) will need to be changed.
tv.on();
If a new device is added, this
etc code would need to be
changed.
The Command
Sends a message to a device (On or Off)
Handle the undo of a message
Possible future enhancements
Logging request
Queue request
05/09/2024 9
Command Interface (pg203)
public interface Command {
public void execute();
}
10
05/09/2024
LightOnCommand (pg203)
public class LightOnCommand implements Command {
The command is
Light light; composed of a vendor
class.
public LightOnCommand(Light light) {
this.light = light;
} Constructor takes the
vendor class as
parameter.
public void execute() {
light.on();
}
}
Here the command delegates
execution to the vendor class.
Note: This is a simple
example..there could be more
steps.
05/09/2024 11
SimpleRemoteControl (pg204)
This version of the
public class SimpleRemoteControl { remote just has one
Command slot; slot.
public SimpleRemoteControl() {}
remote.setCommand(lightOn);
Set the command and press
remote.buttonWasPressed();
button
remote.setCommand(garageOpen);
remote.buttonWasPressed();
05/09/2024 13
The Command Pattern
GoF Intent: “Encapsulates a request as an object,
thereby letting you parameterize other objects with
different requests, queue or log requests, and support
undoable operations.”
05/09/2024 14
05/09/2024 15
Definitions (see Diagram on pg 207)
Client (RemoteControlTest) – creates command and
associates command with receiver.
05/09/2024 17
Lab Part II
The customer wants to be able to turn the DVD and TV
on (and off) at the same time.
05/09/2024 18
Lab Part III (Design Challenge!)
Look at the LightOnCommand and LightOffCommand on
pg 217.
05/09/2024 19
Lab Part I Answer
public class DVDOnCommand : Command {
DVD dvd;
public DVDOnCommand(DVD d)
{
this.dvd = d;
}
05/09/2024 20
Lab Part I Answer (cont)
public class DVDOffCommand : Command {
DVD dvd;
public DVDOffCommand(DVD d)
{
this.dvd = d;
}
05/09/2024 21
Lab Part II Answer
public class DVDTvOnCommand : Command {
DVD dvd;
TV tv;
public DVDTvOnCommand(DVD d, TV t)
{
this.dvd = d;
this.tv = t;
}
05/09/2024 22
Lab Part III (Answer)
public enum CommandState
{
NOTSET,
ON,
OFF
}
05/09/2024 23
Lab Part III (Answer)
public abstract class CommandBase
{
CommandState state;
public CommandBase()
{
state = CommandState.NOTSET;
}
05/09/2024 24
public void on() {
state = CommandState.ON;
We don’t want on(), off(), and
executeOn();
undo() to be overridden.
}
public LightCommand(Light l) {
this.light = l;
}
05/09/2024 26
Lab Part III
The client that calls this code…
05/09/2024 27
History of Undo Operations
If the Undo button is pressed multiple times, we want to
undo each command that had been previously applied.
05/09/2024 30
Simple Logging
Changes to RemoteControl…
05/09/2024 31
Complex Logging
Let’s say we had a spreadsheet application and we know it
may crash often.
05/09/2024 32
Complex Logging
public void onButtonWasPushed(int slot) { Once again, we can
onCommands[slot].execute(); make these
StoreToDisk(onCommands[slot]); changes in one
} place (the Invoker)
• Open
• Save
• Print
05/09/2024 34
Question
Imagine that there is a Command for each action
Open
Save
Print
Copy
05/09/2024 35
Possible Solutions
In both the Menu and Toolbar click events, write all of the
code for performing the command.
(or) Consolidate all of the logic in one place and have the
Menu and Toolbar events call the same logic.
05/09/2024 36
Disadvantages
The developer would need to enforce that each UI
element calls the right command.
saveMenuItem.Enabled = false;
saveButton.Enabled = false;
saveToolbar.Enabled = false
05/09/2024 37
Command Management Framework
Based on the Command Pattern
05/09/2024 38
Example
// Create Command Manager object
cmdMgr = new CommandManager();
05/09/2024 39
Command Manager
The Commands property
contains a list of all
possible Commands.
CommandsList contains
a List object internally for
storing each possible
Command. It also has a
reference to
CommandManager.
05/09/2024 40
Command Object
//Delegates
public delegate void ExecuteHandler(Command cmd);
public delegate void UpdateHandler(Command cmd);
// Events
public event ExecuteHandler OnExecute;
public event UpdateHandler OnUpdate;
05/09/2024 42
Command: Execute() and ProcessUpdates()
// Methods to trigger events
public void Execute()
{
Will call the function
if (OnExecute != null)
passed in as
OnExecute(this);
ExecuteHandler
}
43
Re-look at EditCopy
cmdMgr.Commands.Add( new Command(
"EditCopy",
new Command.ExecuteHandler(OnCopy),
new Command.UpdateHandler(UpdateCopyCommand)));
Command #1
Tag = “Edit Copy”
OnExecute = OnCopy
OnUpdate = UpdateCopyCommand
Command #2
Tag = “File Open”
OnExecute = OnFileOpen
OnUpdate = null
05/09/2024 45
Associating UI Elements to a Command
//Associate Command “Edit Copy” with different UI elements
//(Menu and Toolbar)
cmdMgr.Commands["EditCopy"].CommandInstances.Add(
new Object[]{mnuEditCopy, tlbMain.Buttons[4]});
05/09/2024 46
CommandInstances
05/09/2024 47
So far..
Two items:
mnuEditCopy
tlbMain.Buttons[4]
Command #1
Tag = “Edit Copy”
OnExecute = OnCopy
OnUpdate = UpdateCopyCommand
All we have done so far
is store information…
05/09/2024 48
How do we enable a Command???
In CommandManager, there is an event handler for the
Application Idle Event:
while ( myEnumerator.MoveNext() )
{
Command cmd = myEnumerator.Value as Command;
if (cmd != null)
cmd.ProcessUpdates();
Are you enabled???
}
}
49
Command.ProcessUpdates()
internal void ProcessUpdates()
{
if (OnUpdate != null)
OnUpdate(this);
}
05/09/2024 50
Command.Enabled Property
The psuedo-code for this property is the following:
05/09/2024 51
Command.Enabled (Psuedo-Code)
foreach (object in CommandInstances)
if (object is MenuItem) {
MenuItem m = (MenuItem)object;
m.Enabled = (true or false);
End for
commandExecutor =
GetCommandExecutor(typeof(object);
End for
05/09/2024 53
CommandExecutor
05/09/2024 54
CommandExecutor
public abstract class CommandExecutor
{
public abstract void Enable(object item, bool bEnable);
}
05/09/2024 55
Command.Enabled (Real Code)
public bool Enabled
{
get
{
return enabled;
}
set
{
enabled = value;
foreach(object instance in commandInstances)
{
Manager.GetCommandExecutor(instance).Enable(
instance, enabled);
}
}
}
05/09/2024 57
Called when
MenuCommandExecutor we added UI
element to
public class MenuCommandExecutor : CommandExecutor Command
{
public override void InstanceAdded(object item, Command cmd)
{
MenuItem mi = (MenuItem)item;
mi.Click += new System.EventHandler(menuItem_Click);
} 05/09/2024 58
Example (Again)
// Create Command Manager object
cmdMgr = new CommandManager();
05/09/2024 59
Confused?
http://msdn.microsoft.com/en-us/magazine/cc188928.aspx
05/09/2024 60
Distributed Command Pattern
Address Chat Window Problem
http://www.codeproject.com/KB/architecture/
distributedcommandpattern.aspx
05/09/2024 61