My question is related to the command pattern, where we have the following abstraction (C# code) :
public interface ICommand
{
void Execute();
}
<
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().
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 working 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).
In the constructor and stored as fields.
You will also want to eventually make your ICommands serializable for the undo stack or file persistence.
You'll need to associate the parameters with the command object, either by constructor or setter injection (or equivalent). Perhaps something like this:
public class DeletePersonCommand: ICommand
{
private Person personToDelete;
public DeletePersonCommand(Person personToDelete)
{
this.personToDelete = personToDelete;
}
public void Execute()
{
doSomethingWith(personToDelete);
}
}
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.
There are some options:
You could pass parameters by properties or constructor.
Other option could be:
interface ICommand<T>
{
void Execute(T args);
}
And encapsulate all command parameters in a value object.