Command and Adapter Pattern


Published on

This is Class 4 on a 6 week course I taught on Software Design Patterns.

This course goes over Command and Adapter pattern.

Class based on "Head First Design Patterns."

Published in: Technology, Business
  • Be the first to comment

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • 13 November 2008
  • Note: In the RemoteControl example, each Command wrapped a Receiver object and told the Reciever to do something. In this example, the Command is given the logic externally. 13 November 2008
  • Possible Side Discussion on Factory? 13 November 2008
  • Command and Adapter Pattern

    1. 1. Design Patterns 05/28/10 Week 4: Command and Adapter Jonathan Simon [email_address]
    2. 2. Agenda <ul><li>Command Pattern </li></ul><ul><ul><li>Head First Example (Remote Control) </li></ul></ul><ul><ul><li>Lab </li></ul></ul><ul><ul><li>History of Undo Operations </li></ul></ul><ul><ul><li>Simple Logging </li></ul></ul><ul><ul><li>Complex Logging </li></ul></ul><ul><ul><li>Case Study: Command Management </li></ul></ul><ul><ul><li>Distributed Command Pattern </li></ul></ul><ul><li>Adapter Pattern </li></ul><ul><ul><li>Lab </li></ul></ul><ul><ul><li>Two Way Adpater </li></ul></ul>05/28/10
    3. 3. Remote Control <ul><li>Given remote control with seven programmable slots. </li></ul><ul><li>A different device can be put into each slot. </li></ul><ul><li>There is an On and Off switch for each device slot. </li></ul><ul><li>Global Undo button undoes the last button pressed. </li></ul><ul><li>Also given a CD with different vendor classes that have already been written (for the different devices, TV, Light, Sprinkler, etc) </li></ul>05/28/10
    4. 4. First Thoughts <ul><li>We know that there are seven programmable slots for different devices…so each device may possibly adhere to some common interface. </li></ul><ul><li>We know that we need to turn each device “on” or “off” that needs to be commonly done for any device. </li></ul><ul><li>Undo needs to work for any device as well. </li></ul>05/28/10
    5. 5. What Varies? What stays the same? <ul><li>What Varies </li></ul><ul><ul><li>The actual device assigned to a slot </li></ul></ul><ul><ul><li>The instruction for “On” on a specific device </li></ul></ul><ul><ul><li>The instruction for “Off” on a specific device </li></ul></ul><ul><li>What Stays the Same </li></ul><ul><ul><li>Device with seven slots </li></ul></ul><ul><ul><li>Capability to assign a slot to a device </li></ul></ul><ul><ul><li>Capability to request that a device turn On or Off </li></ul></ul><ul><ul><li>Capability to undo the last action requested against the device </li></ul></ul>05/28/10
    6. 6. The Vendor Classes (pg 194) <ul><li>Vendor classes have been provided to us via a CD. </li></ul><ul><ul><li>Ceiling Light </li></ul></ul><ul><ul><li>TV </li></ul></ul><ul><ul><li>Hottub </li></ul></ul><ul><li>We know that each device needs an “On” or “Off” state. </li></ul><ul><ul><li>Since the capability to turn a device “On” or “Off” is something that “stays the same”. </li></ul></ul><ul><ul><li>However, each vendor class has their own unique way of doing “On” or “Off”. </li></ul></ul>05/28/10
    7. 7. One possible solution… <ul><li>if (slot1 == Light) </li></ul><ul><li>light.on(); </li></ul><ul><li>Else if (slot1 == Hottub) { </li></ul><ul><li>hottub.prepareJets(); </li></ul><ul><li>hottub.jetsOn(); </li></ul><ul><li>} Else if (slot1 == TV) </li></ul><ul><li>tv.on(); </li></ul><ul><li>etc </li></ul>05/28/10 Problems: The Remote needs to be aware of all the details about turning a device on (or off). If device On/Off mechanism changes, the Remote code will need to be changed. If a new device is added, this code would need to be changed. Is this Open for Extension?? Also…what about undo????
    8. 8. Separation of Concerns <ul><li>The Vendor Class </li></ul><ul><ul><li>One (or more) methods that define “On” </li></ul></ul><ul><ul><li>One (or more) methods that define “Off” </li></ul></ul><ul><li>The Command </li></ul><ul><ul><li>Sends a message to a device (On or Off) </li></ul></ul><ul><ul><li>Handle the undo of a message </li></ul></ul><ul><ul><li>Possible future enhancements </li></ul></ul><ul><ul><ul><li>Logging request </li></ul></ul></ul><ul><ul><ul><li>Queue request </li></ul></ul></ul><ul><li>The Remote – handles one or more Commands. The Remote doesn’t know anything about the actual vendor class specifics. </li></ul>05/28/10
    9. 9. The Command Pattern <ul><li>“ Allows you to decouple the requestor of the action from the object that performs the action.” </li></ul><ul><li>“ A Command object encapsulates a request to do something.” </li></ul><ul><ul><li>Note: A Command object handles a single request. </li></ul></ul>05/28/10
    10. 10. Command Interface (pg203) <ul><li>public interface Command { </li></ul><ul><li>public void execute(); </li></ul><ul><li>} </li></ul><ul><li>The Command interface (in this example) just does one thing..executes a command. </li></ul>05/28/10
    11. 11. LightOnCommand (pg203) <ul><li>public class LightOnCommand implements Command { </li></ul><ul><li>Light light; </li></ul><ul><li>public LightOnCommand(Light light) { </li></ul><ul><li>this.light = light; </li></ul><ul><li>} </li></ul><ul><li>public void execute() { </li></ul><ul><li>light.on(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 The command is composed of a vendor class. Constructor takes the vendor class as parameter. Here the command delegates execution to the vendor class. Note : This is a simple example..there could be more steps.
    12. 12. SimpleRemoteControl (pg204) <ul><li>public class SimpleRemoteControl { </li></ul><ul><li>Command slot; </li></ul><ul><li>public SimpleRemoteControl() {} </li></ul><ul><li>public void setCommand(Command command) { </li></ul><ul><li>slot = command; </li></ul><ul><li>} </li></ul><ul><li>public void buttonWasPressed() { </li></ul><ul><li>slot.execute(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 This version of the remote just has one slot. setCommand assigns a Command to a slot. Tells the command to execute. Note that any command would work here. The remote doesn’t know anything about the specific vendor class.
    13. 13. RemoteControlTest (pg204) <ul><li>SimpleRemoteControl remote = new SimpleRemoteControl(); </li></ul><ul><li>Light light = new Light(); </li></ul><ul><li>GarageDoor garageDoor = new GarageDoor(); </li></ul><ul><li>LightOnCommand lightOn = </li></ul><ul><li>new LightOnCommand(light); </li></ul><ul><li>GarageDoorOpenCommand garageOpen = </li></ul><ul><li> new GarageDoorOpenCommand(garageDoor); </li></ul><ul><li>remote.setCommand(lightOn); </li></ul><ul><li>remote.buttonWasPressed(); </li></ul><ul><li>remote.setCommand(garageOpen); </li></ul><ul><li>remote.buttonWasPressed(); </li></ul>05/28/10 Create two vendor classes. Create two commands based on these vendor classes. Set the command and press button
    14. 14. The Command Pattern <ul><li>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.” </li></ul><ul><li>See diagrams on pg 206 </li></ul><ul><ul><li>Command encapsulates a Receiver object </li></ul></ul><ul><ul><li>Different commands can fit into a Remote Slot (which exists in the Remote Control) </li></ul></ul>05/28/10
    15. 15. Definitions (see Diagram on pg 207) <ul><li>Client (RemoteControlTest) – creates command and associates command with receiver. </li></ul><ul><li>Receiver (TV, HotTub, ec)– knows how to perform the work. </li></ul><ul><li>Concrete Command (LightOnCommand) - implementation of Command interface </li></ul><ul><li>Command Interface – defines interface for all commands. </li></ul><ul><li>Invoker (Remote Control) – holds reference to a command and calls execute() method against it. </li></ul>
    16. 16. Lab Part I <ul><li>We get a new vendor class for DVD. To turn on the DVD, call the function TurnPowerOn(). To turn off, you call TurnPowerOff(). </li></ul><ul><li>Create an On and Off command object for the DVD player. </li></ul>05/28/10
    17. 17. Lab Part II <ul><li>The customer wants to be able to turn the DVD and TV on (and off) at the same time. </li></ul><ul><li>Create a command that will set up the DVD and TV with one button click. </li></ul>05/28/10
    18. 18. Lab Part III (Design Challenge!) <ul><li>Look at the LightOnCommand and LightOffCommand on pg 217. </li></ul><ul><li>Note that there is a duplication of code between these two objects. </li></ul><ul><li>Can you create an abstract class called Command that can help remove this duplication of code…and yet support Undo?? </li></ul>05/28/10
    19. 19. Lab Part I Answer <ul><li>public class DVDOnCommand : Command { </li></ul><ul><li> DVD dvd; </li></ul><ul><li>public DVDOnCommand(DVD d) </li></ul><ul><li>{ </li></ul><ul><li>this.dvd = d; </li></ul><ul><li>} </li></ul><ul><li>public void execute() </li></ul><ul><li>{ </li></ul><ul><li>dvd.TurnPowerOn(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    20. 20. Lab Part I Answer (cont) <ul><li>public class DVDOffCommand : Command { </li></ul><ul><li> DVD dvd; </li></ul><ul><li>public DVDOffCommand(DVD d) </li></ul><ul><li>{ </li></ul><ul><li>this.dvd = d; </li></ul><ul><li>} </li></ul><ul><li>public void execute() </li></ul><ul><li>{ </li></ul><ul><li>dvd.TurnPowerOff(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    21. 21. Lab Part II Answer <ul><li>public class DVDTvOnCommand : Command { </li></ul><ul><li>DVD dvd; </li></ul><ul><li>TV tv; </li></ul><ul><li>public DVDTvOnCommand(DVD d, TV t) </li></ul><ul><li>{ </li></ul><ul><li>this.dvd = d; </li></ul><ul><li> = t; </li></ul><ul><li>} </li></ul><ul><li>public void execute() </li></ul><ul><li>{ </li></ul><ul><li>tv.on(); </li></ul><ul><li>tv.changeInputToDvd(); </li></ul><ul><li>dvd.TurnPowerOn(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    22. 22. Lab Part III (Answer) <ul><li>public enum CommandState </li></ul><ul><li>{ </li></ul><ul><li>NOTSET, </li></ul><ul><li>ON, </li></ul><ul><li>OFF </li></ul><ul><li>} </li></ul>05/28/10
    23. 23. Lab Part III (Answer) <ul><li>public abstract class CommandBase </li></ul><ul><li>{ </li></ul><ul><li>CommandState state; </li></ul><ul><li>public CommandBase() </li></ul><ul><li>{ </li></ul><ul><li>state = CommandState.NOTSET; </li></ul><ul><li>} </li></ul><ul><li> abstract protected void executeOn(); </li></ul><ul><li>abstract protected void executeOff(); </li></ul>05/28/10
    24. 24. <ul><li>public void on() { </li></ul><ul><li> state = CommandState.ON; </li></ul><ul><li> executeOn(); </li></ul><ul><li>} </li></ul><ul><li>public void off() { </li></ul><ul><li>state = CommandState.OFF; </li></ul><ul><li>executeOff(); </li></ul><ul><li>} </li></ul><ul><li>public void undo() { </li></ul><ul><li> if (state == CommandState.ON) </li></ul><ul><li>off(); </li></ul><ul><li>else if (state == CommandState.OFF) </li></ul><ul><li>on(); </li></ul><ul><li>else if (state == CommandState.NOTSET) </li></ul><ul><li>{ </li></ul><ul><li>//do nothing </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>We don’t want on(), off(), and undo() to be overridden.
    25. 25. Lab Part III <ul><li>public class LightCommand : CommandBase </li></ul><ul><li>{ </li></ul><ul><li>Light light; </li></ul><ul><li>public LightCommand(Light l) { </li></ul><ul><li>this.light = l; </li></ul><ul><li>} </li></ul><ul><li>protected override void executeOn() </li></ul><ul><li>{ </li></ul><ul><li>light.on(); </li></ul><ul><li>} </li></ul><ul><li>protected override void executeOff() </li></ul><ul><li>{ </li></ul><ul><li>; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    26. 26. Lab Part III <ul><li>The client that calls this code… </li></ul><ul><li>CommandBase c = new LightCommand(new Light()); </li></ul><ul><li>c.on(); </li></ul><ul><li>c.undo(); </li></ul>05/28/10
    27. 27. History of Undo Operations <ul><li>If the Undo button is pressed multiple times, we want to undo each command that had been previously applied. </li></ul><ul><li>Which object should we enhance to store a history of each command applied? Why? </li></ul><ul><ul><li>Client (RemoteControlTest) </li></ul></ul><ul><ul><li>Receiver (TV, DVD, etc) </li></ul></ul><ul><ul><li>ConcreteCommand (LightOnCommand, LightOffCommand, etc) </li></ul></ul><ul><ul><li>Invoker (RemoteControl) </li></ul></ul><ul><li>We need to be able to add commands to a list and then later get the most recent one. What kind of object can we use? </li></ul>05/28/10
    28. 28. History of Undo Operations <ul><li>public class RemoteControl { </li></ul><ul><li>Stack<Command> undoStack; //this gets initialized in //constructor. </li></ul><ul><li>public void onButtonWasPushed(int slot) { </li></ul><ul><li>onCommands[slot].execute(); </li></ul><ul><li>undoStack.push(onCommands[slot]); </li></ul><ul><li>} </li></ul><ul><li>public void offButtonWasPushed(int slot) { </li></ul><ul><li>offCommands[slot].execute(); </li></ul><ul><li>undoStack.push(offCommands[slot]); </li></ul><ul><li>} </li></ul><ul><li>public void undoButtonWasPushed() { </li></ul><ul><li>Command c = undoStack.pop(); </li></ul><ul><li>c.undo(); </li></ul><ul><li> } </li></ul>
    29. 29. Simple Logging <ul><li>We want to enhance the Remote Control again to log every time a Command is executed (on or off). </li></ul><ul><li>Which object should we enhance?? </li></ul>05/28/10
    30. 30. Simple Logging <ul><li>Changes to RemoteControl… </li></ul><ul><li>public void onButtonWasPushed(int slot) { </li></ul><ul><li>onCommands[slot].execute(); </li></ul><ul><li>//Log here </li></ul><ul><li>} </li></ul><ul><li>public void offButtonWasPushed(int slot) { </li></ul><ul><li>offCommands[slot].execute(); </li></ul><ul><li>//Log here </li></ul><ul><li>} </li></ul>05/28/10 Advantage: We can add logging in the Invoker. No change is needed in any of the Command or Receiver objects!
    31. 31. Complex Logging <ul><li>Let’s say we had a spreadsheet application and we know it may crash often. </li></ul><ul><li>For failure recovery, we could periodically store a backup of the spreadsheet every 5 minutes...or we could periodically persist the list of commands executed on the spreadsheet since the last save point. </li></ul><ul><li>When a crash occurs, we load the last saved document and re-apply the persisted commands. </li></ul>05/28/10
    32. 32. <ul><li>public void onButtonWasPushed(int slot) { </li></ul><ul><li>onCommands[slot].execute(); </li></ul><ul><li>StoreToDisk(onCommands[slot]); </li></ul><ul><li>} </li></ul><ul><li>public void offButtonWasPushed(int slot) { </li></ul><ul><li>offCommands[slot].execute(); </li></ul><ul><li>StoreToDisk(offCommands[slot]); </li></ul><ul><li>} </li></ul><ul><li>public void SaveButtonPressed() { </li></ul><ul><li>//Delete stored commands from disk. </li></ul><ul><li>} </li></ul><ul><li>public void RestoreCommands() { </li></ul><ul><li>//load last saved state </li></ul><ul><li>Commands[] storedCommands = GetCommandsFromDisk(); </li></ul><ul><li>//for each Command, call execute() </li></ul><ul><li>} </li></ul>Complex Logging 05/28/10 Once again, we can make these changes in one place (the Invoker)
    33. 33. Case Study: Command Management 05/28/10 <ul><li>The File menu contains the items: </li></ul><ul><li>Open </li></ul><ul><li>Save </li></ul><ul><li>Print </li></ul><ul><li>Also menu item “Edit  Copy “ which is enabled when text is selected. </li></ul><ul><li>Same toolbar buttons for each menu item. </li></ul>
    34. 34. Question <ul><li>Imagine that there is a Command for each action </li></ul><ul><ul><li>Open </li></ul></ul><ul><ul><li>Save </li></ul></ul><ul><ul><li>Print </li></ul></ul><ul><ul><li>Copy </li></ul></ul><ul><li>How would you associate each Menu/Toolbar pair with a Command? </li></ul>05/28/10
    35. 35. Possible Solutions <ul><li>In both the Menu and Toolbar click events, write all of the code for performing the command. </li></ul><ul><li>(or) Consolidate all of the logic in one place and have the Menu and Toolbar events call the same logic. </li></ul><ul><li>What are the disadvantages of this approach? </li></ul>05/28/10
    36. 36. Disadvantages <ul><li>The developer would need to enforce that each UI element calls the right command. </li></ul><ul><li>Managing state can be become an issue. </li></ul><ul><ul><li>For example, input form with three different UI elements for Save. (Menu Item, Toolbar Button, Button next to the Form) </li></ul></ul><ul><ul><li>When the form is in Edit mode all of these elements should be Enabled. When the form is not in Edit mode, they need to be disabled. </li></ul></ul><ul><ul><li>saveMenuItem.Enabled = false; </li></ul></ul><ul><ul><li>saveButton.Enabled = false; </li></ul></ul><ul><ul><li>saveToolbar.Enabled = false </li></ul></ul>05/28/10
    37. 37. Command Management Framework <ul><li>Based on the Command Pattern </li></ul><ul><li>Framework for associating multiple UI Elements to the same Command </li></ul><ul><li>Can associate UI Elements and Commands in one place. </li></ul><ul><li>You can send a message to a Command </li></ul><ul><ul><li>“ Tell all of your UI Elements to Turn On or Off” </li></ul></ul>05/28/10
    38. 38. Example <ul><li>// Create Command Manager object </li></ul><ul><li>cmdMgr = new CommandManager(); </li></ul><ul><li>//Create a Command “Edit Copy” with a Execute and Copy </li></ul><ul><li>//functionality. </li></ul><ul><li>cmdMgr.Commands.Add( new Command( </li></ul><ul><li>&quot;EditCopy&quot;, </li></ul><ul><li>new Command.ExecuteHandler(OnCopy), </li></ul><ul><li>new Command.UpdateHandler(UpdateCopyCommand))); </li></ul><ul><li>//Associate Command “Edit Copy” with different UI elements (Menu and Toolbar) </li></ul><ul><li>cmdMgr.Commands[&quot;EditCopy&quot;].CommandInstances.Add( </li></ul><ul><li>new Object[]{mnuEditCopy, tlbMain.Buttons[4]}); </li></ul>05/28/10
    39. 39. Command Manager 05/28/10 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.
    40. 40. Command Object ExecuteHandler = delegate that represents the logic for executing the actual Command logic. Triggered when the command is executed. Gets associated with OnExecute event. UpdateHandler = delegate that represents the logic for executing the logic to update the state of a command. (For example, Edit  Copy should be enabled if text has been selected). Associated with OnUpdate event.
    41. 41. Command Constructor <ul><li>public Command( string strTag, </li></ul><ul><li>ExecuteHandler handlerExecute, </li></ul><ul><li>UpdateHandler handlerUpdate) </li></ul><ul><li>{ </li></ul><ul><li> this.strTag = strTag; </li></ul><ul><li>OnExecute += handlerExecute; </li></ul><ul><li>OnUpdate += handlerUpdate; </li></ul><ul><li>} </li></ul><ul><li>//Delegates </li></ul><ul><li>public delegate void ExecuteHandler(Command cmd); </li></ul><ul><li>public delegate void UpdateHandler(Command cmd); </li></ul><ul><li>// Events </li></ul><ul><li>public event ExecuteHandler OnExecute; </li></ul><ul><li>public event UpdateHandler OnUpdate; </li></ul>05/28/10 Associates events to delegates
    42. 42. Command: Execute() and ProcessUpdates() <ul><li>// Methods to trigger events </li></ul><ul><li>public void Execute() </li></ul><ul><li>{ </li></ul><ul><li>if (OnExecute != null) </li></ul><ul><li>OnExecute(this); </li></ul><ul><li>} </li></ul><ul><li>internal void ProcessUpdates() </li></ul><ul><li>{ </li></ul><ul><li>if (OnUpdate != null) </li></ul><ul><li>OnUpdate(this); </li></ul><ul><li>} </li></ul>Will call the function passed in as ExecuteHandler Will call the function passed in as UpdateHandler How is this Command.Execute() different than the RemoteControl example??
    43. 43. Re-look at EditCopy <ul><li>cmdMgr.Commands.Add( new Command( </li></ul><ul><li>&quot;EditCopy&quot;, </li></ul><ul><li>new Command.ExecuteHandler(OnCopy), </li></ul><ul><li>new Command.UpdateHandler(UpdateCopyCommand))); </li></ul><ul><li>//Here is the logic of the actual command </li></ul><ul><li>public void OnCopy(Command cmd) { </li></ul><ul><li>Clipboard.SetDataObject(txtEditor.SelectedText); </li></ul><ul><li>} </li></ul><ul><li>//Defines the condition for when the command should be “on” </li></ul><ul><li>public void UpdateCopyCommand(Command cmd) { </li></ul><ul><li>cmd.Enabled = txtEditor.SelectedText.Length > 0; </li></ul><ul><li>} </li></ul>05/28/10 Will discuss later
    44. 44. So far.. 05/28/10 Command #1 Tag = “Edit Copy” OnExecute = OnCopy OnUpdate = UpdateCopyCommand Command #2 Tag = “File Open” OnExecute = OnFileOpen OnUpdate = null
    45. 45. Associating UI Elements to a Command <ul><li>//Associate Command “Edit Copy” with different UI elements </li></ul><ul><li>//(Menu and Toolbar) </li></ul><ul><li>cmdMgr.Commands[&quot;EditCopy&quot;].CommandInstances.Add( </li></ul><ul><li>new Object[]{mnuEditCopy, tlbMain.Buttons[4]}); </li></ul>05/28/10 What object contains the CommandInstances property??
    46. 46. CommandInstances 05/28/10 Contain a list of all UI Elements associated with a Command
    47. 47. So far.. 05/28/10 Command #1 Tag = “Edit Copy” OnExecute = OnCopy OnUpdate = UpdateCopyCommand Two items: mnuEditCopy tlbMain.Buttons[4] All we have done so far is store information…
    48. 48. How do we enable a Command??? <ul><li>In CommandManager, there is an event handler for the Application Idle Event: </li></ul><ul><li>private void OnIdle(object sender, System.EventArgs args) </li></ul><ul><li>{ </li></ul><ul><li>IDictionaryEnumerator myEnumerator = </li></ul><ul><li>(IDictionaryEnumerator)Commands.GetEnumerator(); </li></ul><ul><li>while ( myEnumerator.MoveNext() ) </li></ul><ul><li>{ </li></ul><ul><li>Command cmd = myEnumerator.Value as Command; </li></ul><ul><li>if (cmd != null) </li></ul><ul><li>cmd.ProcessUpdates(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>Are you enabled???
    49. 49. Command.ProcessUpdates() <ul><li>internal void ProcessUpdates() </li></ul><ul><li>{ </li></ul><ul><li>if (OnUpdate != null) </li></ul><ul><li>OnUpdate(this); </li></ul><ul><li>} </li></ul><ul><li>For Edit Copy, the following code will be called: </li></ul><ul><li>public void UpdateCopyCommand(Command cmd) { </li></ul><ul><li>cmd.Enabled = txtEditor.SelectedText.Length > 0; </li></ul><ul><li>} </li></ul>05/28/10 If we do need to enable (or disable) the Command, who do we need to tell to “go enable/disable yourself?”
    50. 50. Command.Enabled Property <ul><li>The psuedo-code for this property is the following: </li></ul><ul><ul><li>Enabled = true or false //we got this information externally </li></ul></ul><ul><ul><li>foreach (object in CommandInstances) </li></ul></ul><ul><ul><li>//enable or disable yourself. </li></ul></ul><ul><ul><li>End for </li></ul></ul><ul><li>So if there is a Menu Item, ToolBar, etc, we want to enable each one. But note that CommandInstances is just a collection of generic objects… </li></ul>05/28/10
    51. 51. Command.Enabled (Psuedo-Code) <ul><ul><li>foreach (object in CommandInstances) </li></ul></ul><ul><ul><li>if (object is MenuItem) { </li></ul></ul><ul><ul><li>MenuItem m = (MenuItem)object; </li></ul></ul><ul><ul><li>m.Enabled = (true or false); </li></ul></ul><ul><ul><li> } else if (object is Toolbar) { </li></ul></ul><ul><ul><li>Toolbar t = (Toolbar)object; </li></ul></ul><ul><ul><li>t.Enabled = (true or false); </li></ul></ul><ul><ul><li> } else {…} </li></ul></ul><ul><ul><li>End for </li></ul></ul>05/28/10 Question: Any problems with this code???
    52. 52. Command.Enabled (Psuedo-Code) <ul><ul><li>foreach (object in CommandInstances) </li></ul></ul><ul><ul><li>commandExecutor = GetCommandExecutor(typeof(object); </li></ul></ul><ul><ul><li>commandExecutor.Enable( object, true/false); </li></ul></ul><ul><ul><li>End for </li></ul></ul>05/28/10
    53. 53. CommandExecutor 05/28/10 Enable() is abstract. Toolbar and Menu subclasses must define how Enable needs to work.
    54. 54. CommandExecutor <ul><li>public abstract class CommandExecutor </li></ul><ul><li>{ </li></ul><ul><li>public abstract void Enable(object item, bool bEnable); </li></ul><ul><li>} </li></ul><ul><li>public class MenuCommandExecutor : CommandExecutor </li></ul><ul><li>{ </li></ul><ul><li>public override void Enable(object item, bool bEnable) </li></ul><ul><li>{ </li></ul><ul><li>MenuItem mi = (MenuItem)item; </li></ul><ul><li>mi.Enabled = bEnable; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    55. 55. Command.Enabled (Real Code) <ul><li>public bool Enabled </li></ul><ul><li>{ </li></ul><ul><li>get </li></ul><ul><li>{ </li></ul><ul><li>return enabled; </li></ul><ul><li>} </li></ul><ul><li>set </li></ul><ul><li>{ </li></ul><ul><li>enabled = value; </li></ul><ul><li>foreach(object instance in commandInstances) </li></ul><ul><li>{ </li></ul><ul><li>Manager.GetCommandExecutor(instance).Enable( </li></ul><ul><li>instance, enabled); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>CommandManager actually contains all possible CommandExecutors. These are registered during start-up for each possible type of UI element. (CommandManager constructor)
    56. 56. CommandExecutor - Execution <ul><li>These objects also help establish the connection between the UI Event and a Command. </li></ul><ul><li>For example, MenuCommandExecutor establishes a link between the event MenuItem.Click and the associated Command execution method (command.Execute) </li></ul>05/28/10
    57. 57. MenuCommandExecutor <ul><li>public class MenuCommandExecutor : CommandExecutor </li></ul><ul><li>{ </li></ul><ul><li>public override void InstanceAdded(object item, Command cmd) </li></ul><ul><li>{ </li></ul><ul><li>MenuItem mi = (MenuItem)item; </li></ul><ul><li>mi.Click += new System.EventHandler(menuItem_Click); </li></ul><ul><li>base.InstanceAdded(item, cmd); //Stores UI/Command //relationship in hashtable </li></ul><ul><li>} </li></ul><ul><li>private void menuItem_Click(object sender, System.EventArgs e) </li></ul><ul><li>{ </li></ul><ul><li>Command cmd = GetCommandForInstance(sender); </li></ul><ul><li>cmd.Execute(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 Called when we added UI element to Command
    58. 58. Example (Again) <ul><li>// Create Command Manager object </li></ul><ul><li>cmdMgr = new CommandManager(); </li></ul><ul><li>//Create a Command “Edit Copy” with a Execute and Copy </li></ul><ul><li>//functionality. </li></ul><ul><li>cmdMgr.Commands.Add( new Command( </li></ul><ul><li>&quot;EditCopy&quot;, </li></ul><ul><li>new Command.ExecuteHandler(OnCopy), </li></ul><ul><li>new Command.UpdateHandler(UpdateCopyCommand))); </li></ul><ul><li>//Associate Command “Edit Copy” with different UI elements (Menu and Toolbar) </li></ul><ul><li>cmdMgr.Commands[&quot;EditCopy&quot;].CommandInstances.Add( </li></ul><ul><li>new Object[]{mnuEditCopy, tlbMain.Buttons[4]}); </li></ul>05/28/10
    59. 59. Confused? <ul><li> </li></ul><ul><li>You can download the code! </li></ul>05/28/10
    60. 60. Distributed Command Pattern <ul><li>Address Chat Window Problem </li></ul><ul><li> </li></ul>05/28/10
    61. 61. Adapter Pattern <ul><li>GoF Intent: “Converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.” </li></ul><ul><li>Also known as a “Wrapper” </li></ul>05/28/10
    62. 62. Real Life Examples <ul><li>Vendor Classes </li></ul><ul><ul><li>Grid Control </li></ul></ul><ul><ul><li>FTP Utility </li></ul></ul><ul><ul><li>Email Utility </li></ul></ul><ul><li>Other Examples? </li></ul>05/28/10
    63. 63. Drawback <ul><li>If you have Grid control with 20 methods…you may need to create an Adapter with 20 methods that all direct to the grid method. </li></ul><ul><li>Thus..a lot of extra code! </li></ul>05/28/10
    64. 64. Example 1 <ul><li>public class CustomerDL { </li></ul><ul><li>public static void SaveCustomer(string firstName, </li></ul><ul><li> string lastName, </li></ul><ul><li> int age) { </li></ul><ul><li>//Call sp to save customer to database </li></ul><ul><li>//Passes parameters </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10 Generated Code!!!
    65. 65. Example 1 <ul><li>Customer cust1 = new Customer(); </li></ul><ul><li>CustomerDL.SaveCustomer(cust1.firstName, cust1.lastName, cust1.age); </li></ul><ul><li>Customer cust2 = new Customer(); </li></ul><ul><li>CustomerDL.SaveCustomer(cust2.firstName, cust2.lastName, cust2.age); </li></ul>05/28/10 Imagine these lines of code were in different parts of the system. What happens when SaveCustomer gets re-generated?
    66. 66. Example 1 <ul><li>public class CustomerSaveAdapter { </li></ul><ul><li>public static void Save(Customer cust) </li></ul><ul><li>{ </li></ul><ul><li>CustomerDL.SaveCustomer(cust.firstName, cust.lastName, cust.age); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>05/28/10
    67. 67. Lab <ul><li>We have an existing system that interacts with a simple FTP program. This component uses ISimpleFTP interface. </li></ul><ul><li>public interface ISimpleFTP </li></ul><ul><li>{ </li></ul><ul><li>void SendSingleMessage(string message); </li></ul><ul><li>void ConnectToServer(); </li></ul><ul><li>} </li></ul>05/28/10
    68. 68. Lab <ul><li>We just bought a new FTP DLL that comes from a different vendor and has some new functionality: </li></ul><ul><li>public interface IComplexFTP </li></ul><ul><li>{ </li></ul><ul><li>void SendMessages(string[] messages); </li></ul><ul><li>void Connect(); </li></ul><ul><li>string GetDirectoryList(); </li></ul><ul><li>} </li></ul>05/28/10
    69. 69. Lab <ul><li>We have a lot of old code that looks like the following: </li></ul><ul><li>ISimpleFTP f = new SimpleFTP(); </li></ul><ul><li>f.ConnectToServer(); </li></ul><ul><li>f.SendSingleMessage(&quot;message&quot;); </li></ul><ul><li>And we may have new code that looks like the following: </li></ul><ul><li> IComplexFTP cf = new ComplexFTP(); </li></ul><ul><li>cf.Connect(); </li></ul><ul><li>cf.SendMessages(new string[] { &quot;hi&quot;,&quot;there&quot;}); </li></ul><ul><li>string dirList = cf.GetDirectoryList(); </li></ul>05/28/10
    70. 70. Lab <ul><li>We would like to use an adapter for the new DLL ( IComplexFTP), but we need to support the old interface as well. </li></ul><ul><li>Create an adapter that meet this requirement! </li></ul>05/28/10
    71. 71. Answer: Two Way Adapter <ul><li>public class TwoWayFTPAdapter : ISimpleFTP, IComplexFTP </li></ul><ul><li>{ </li></ul><ul><li>private IComplexFTP complexFTP; </li></ul><ul><li>public TwoWayFTPAdapter() </li></ul><ul><li>{ </li></ul><ul><li>complexFTP = new ComplexFTP(); </li></ul><ul><li>} </li></ul><ul><li>//more on next page </li></ul><ul><li>} </li></ul>05/28/10
    72. 72. Answer <ul><li>//ISimpleFTP </li></ul><ul><li>public void SendSingleMessage(string message) </li></ul><ul><li>{ </li></ul><ul><li>complexFTP.SendMessages(new string[] { message }); </li></ul><ul><li>} </li></ul><ul><li>public void ConnectToServer() </li></ul><ul><li>{ </li></ul><ul><li>complexFTP.Connect(); </li></ul><ul><li>} </li></ul>05/28/10
    73. 73. Answer <ul><li>//IComplexFTP </li></ul><ul><li>public void SendMessages(string[] messages) { </li></ul><ul><li>complexFTP.SendMessages(messages); </li></ul><ul><li>} </li></ul><ul><li>public void Connect() { </li></ul><ul><li>complexFTP.Connect(); </li></ul><ul><li>} </li></ul><ul><li>public string GetDirectoryList() { </li></ul><ul><li>return complexFTP.GetDirectoryList(); </li></ul><ul><li>} </li></ul>05/28/10
    74. 74. Answer: Reworked Code <ul><li>ISimpleFTP f = new TwoWayFTPAdapter(); </li></ul><ul><li>f.ConnectToServer(); </li></ul><ul><li>f.SendSingleMessage(&quot;message&quot;); </li></ul><ul><li>IComplexFTP cf = new TwoWayFTPAdapter(); </li></ul><ul><li>cf.Connect(); </li></ul><ul><li>cf.SendMessages(new string[] { &quot;hi&quot;, &quot;there&quot; }); </li></ul><ul><li>string dirList = cf.GetDirectoryList(); </li></ul>05/28/10
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.