views:

430

answers:

5

My understanding of the Command Pattern is that you simply have 1 virtual method 'execute()', and all dependencies that an implementation might have are put in the constructor or through setter injection in the implementation (like discussed here).

However, in the WPF implementation of the pattern, I noticed they are passing a generic argument to the execute() function (explained here).

This seems like a pollution of the interface to me, what would have been the motivation to add a generic parameter to the execute() function?

+1  A: 

It's for databinding. When you bind the command to every object in a list, for example, the current instance is sent to the execute method so that you don't have to keep track of the current instance yourself.

That said, I don't think that the WPF command notion is an implementation of the command pattern, they just share terminology.

klausbyskov
+1  A: 

The reason behind that parameter is the isolation between the creator of the command - who know what command needs to be executed, and the caller - who knows when a command need to be executed.

In certain commands some of the information that needed for the execution is not available to the creator. The caller the fills in the blank by passing a parameter to execute. An example: The creator creates a command that filters a list of records according to some criteria. The list is not available at the creation site, as there are many kinds of lists in the application.

The caller will specify which list needs to be filtered by passing at as a parameter.

Itay
In your example I would expect a specific interface for commands working on a list, that takes a list (or on interface for a list) as parameter, not some kind of generic parameter.
eli
@eli.work: I didn't say the parameter needs be generic. I just said that the data needed for execution is not always available at the site where the command object is created
Itay
My question should have been a bit clearer then: it is the motivation of the generic parameter I'm wondering about. I'll update my question, and thanks for the reply!
eli
+1  A: 

We use a bit changed command pattern, so that in addition to Execute method we have two properties Request and Response and we parametrize them using polymorphism.

Fedor Hajdu
+2  A: 

The canonical command pattern is usually illustrated with nice self-contained commands. In that any information needed by the command is stashed away within the Command object instance (typically via a parameterized constructor).

However in some cases, the parameters needed for Execute may not be available at command-creation time (are known only at runtime). e.g. Imagine a SignOutCommand( username ). The username is determined when the user clicks on the SignOut button after signing in first.

So username is passed in as a generic parameter to Command.Execute(); Each command is free to define its input and cast accordingly e.g. an arbitrary command can require 5 parameters as an object[].

Gishu
I see, but why not defining a separate interface, or create a command implementation that gets the username from somewhere else (like IUserNameGetter)?
eli
@eli.work It's a tradeoff I guess between simplicity and elegance. With an IUserNameGetter, you'd have to create an instance of this new type and store it in the Command object. With every Execute call, the command object will again send a message back to retrieve the username from the GUI. More chatty than just passing in the input. Also with the WPF restriction of accessing GUI from the thread that created it, you may be required to do thread verification and switching in your IUserNameGetter impl (e.g. if Command.Execute is called on a worker thread).
Gishu
A: 

What's wrong with:

public class DeleteCommand : BaseCommand
{
  private Dictionary<string, object> parameters;

  public DeleteCommand(Dictionary<string, object> parameters)
  {
     this.parameters = parameters;
  }

  public void Execute()
  {
     var person = (Person)parameters["Person"];
     var salary = System.Convert.ToDouble(parameters["Salary"]);

     // etc.
  }
}

Now if you have a controller that collects parameters you can pass those through to your commands.

David Robbins