views:

3515

answers:

12

My question is related to the command pattern, where we have the following abstraction (C# code) :

public interface ICommand
{
    Execute();
}

Let's take a simple concrete command, which aims to delete an entity from our application. A Person instance, for example.

I'll have a DeletePersonCommand, which implements ICommand. This command needs the Person to delete as a parameter, in order to delete it when Execute method is called.

What is the best way to manage parametrized commands ? How to pass parameters to commands, before executing them ?

+3  A: 

In the constructor and stored as fields.

You will also want to eventually make your ICommands serializable for the undo stack or file persistence.

Frank Krueger
A: 

DeletePersonCommand can have parameter in its constructor or methods . DeletePersonCommand will have the Execute() and in the execute can check attribute that will be passed by Getter/Setter previously the call of the Execute().

Daok
A: 

I would add any necessary arguments to the constructor of DeletePersonCommand. Then, when Execute() is called, those parameters passed into the object at construction time are used.

Matt Dillard
A: 

Have "Person" implement some sort of IDeletable interface, then make the command take whatever base class or interface your entities use. That way, you can make a DeleteCommand, which tries to cast the entity to an IDeletable, and if that works, call .Delete

public class DeleteCommand : ICommand
{
   public void Execute(Entity entity)
   {
      IDeletable del = entity as IDeletable;
      if (del != null) del.Delete();
   }
}
Joel Martinez
I don't think this works - the whole point of ICommand is that every subclass overrides Execute() _exactly_. This solution requires the caller of Execute() to know more details about the type of command being called.
Matt Dillard
I agree with Matt. That DeleteCommand class wouldn't even compile, anyhow, since it doesn't implement void Execute() as required by the ICommand interface
chadmyers
Using dependency injection, you still have to know everything about the type of command, because you have to new it up! at least this way your code can be generic if you only deal with "Entity". The original response includes info about changing ICommand to include the base class/interface.
Joel Martinez
+20  A: 

You'll need to associate the parameters with the command object, either by constructor or setter injection (or equivalent). Perhaps something like this:

public classs DeletePersonCommand: ICommand
{
     private Person personToDelete;
     public DeletePersonCommand(Person personToDelete)
     {
         this.personToDelete = personToDelete;
     }

     public void Execute()
     {
        doSomethingWith(personToDelete);
     }
}
Blair Conrad
Yeah that exacly what I mean in my post :)
Daok
Exactly what I'd do. For anything that isn't known when the command is constructed, I'd pass in the interface to a service that gets the object when the command is executed. That could be a delegate or lambda expession or another object.
Hamish Smith
+3  A: 

There are some options:

You could pass parameters by properties or constructor.

Other option could be:

interface ICommand<T>
{
    void Execute<T>(T args);
}

And encapsulate all command parameters in a value object.

Juanma
+2  A: 

Pass the person when you create the command object:

ICommand command = new DeletePersonCommand(person);

so that when you execute the command, it already knows everything that it needs to know.

class DeletePersonCommand : ICommand
{
   private Person person;
   public DeletePersonCommand(Person person)
   {
      this.person = person;
   }

   public void Execute()
   {
      RealDelete(person);
   }
}
jop
+2  A: 

In this case, what we've done with our Command objects is to create a Context object which is essentially a map. The map contains name value pairs where the keys are constants and the values are parameters that are used by the Command implementations. Especially useful if you have a Chain of Commands where later commands depend on context changes from earlier commands.

So the actual method becomes

void execute(Context ctx);
A: 

Based on the pattern in C#/WPF the ICommand Interface (System.Windows.Input.ICommand) is defined to take an object as a parameter on the Execute, as well as the CanExecute method.

interface ICommand
            {
                bool CanExecute(object parameter);
                void Execute(object parameter);
            }

This allows you to define your command as a static public field which is an instance of your custom command object that implements ICommand.

public static ICommand DeleteCommand = new DeleteCommandInstance();

In this way the relevant object, in your case a person, is passed in when execute is called. The Execute method can then cast the object and call the Delete() method.

public void Execute(object parameter)
            {
                person target = (person)parameter;
                target.Delete();
            }
TheZenker
A: 

You should create a CommandArgs object to contain the parameters you want to use. Inject the CommandArgs object using the constructor of the Command object.

David Robbins
+3  A: 

Passing the data in via a constructor or setter works, but requires the creator of the command to know the data the command needs...

The "context" idea is really good, and I was worked on (an internal) framework that leveraged it a while back.

If you set up your controller (UI components that interact with the user, CLI interpreting user commands, servlet interpreting incoming parameters and session data, etc) to provide named access to the available data, commands can directly ask for the data they want.

I really like the separation a setup like this allows. Think about layering as follows:

User Interface (GUI controls, CLI, etc)
    |
[syncs with/gets data]
    V
Controller / Presentation Model
    |                    ^
[executes]               |
    V                    |
Commands --------> [gets data by name]
    |
[updates]
    V
Domain Model

If you do this "right", the same commands and presentation model can be used with any type of user interface.

Taking this a step further, the "controller" in the above is pretty generic. The UI controls only need to know the name of the command they'll invoke -- they (or the controller) don't need to have any knowledge of how to create that command or what data that command needs. That's the real advantage here.

For example, you could hold the name of the command to execute in a Map. Whenever the component is "triggered" (usually an actionPerformed), the controller looks up the command name, instantiates it, calls execute, and pushes it on the undo stack (if you use one).

Scott Stanchfield
A: 

My implementation would be this (using the ICommand proposed by Juanma):

public class DeletePersonCommand: ICommand<Person>
{
    public DeletePersonCommand(IPersonService personService)
    {  
        this.personService = personService;
    }

    public void Execute(Person person)
    {
        this.personService.DeletePerson(person);
    }
}

IPersonService could be an IPersonRepository, it depends in what "layer" your command is.

bloparod