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