命令模式:如何将parameter passing给命令?

我的问题是关于命令模式,我们有以下抽象(C#代码):

public interface ICommand { void Execute(); } 

让我们来一个简单的具体命令,其目的是从我们的应用程序中删除一个实体。 例如,一个Person实例。

我将有一个DeletePersonCommand ,它实现了ICommand 。 这个命令需要Person删除一个参数,以便在Execute方法被调用时删除它。

pipe理参数化命令的最好方法是什么? 在执行之前如何传递参数给命令?

您需要通过构造函数或setter注入(或等效)将参数与命令对象相关联。 也许是这样的:

 public class DeletePersonCommand: ICommand { private Person personToDelete; public DeletePersonCommand(Person personToDelete) { this.personToDelete = personToDelete; } public void Execute() { doSomethingWith(personToDelete); } } 

通过构造函数或setter传递数据,但要求命令的创build者知道命令需要的数据…

“上下文”的想法非常好,我正在研究(一个内部)框架,并利用它。

如果您设置了控制器(与用户交互的UI组件,CLI解释用户命令,servlet解释传入参数和会话数据等),以提供对可用数据的命名访问,命令可以直接询问他们想要的数据。

我真的很喜欢这样的分离设置。 考虑分层如下:

 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 

如果你这样做是正确的,相同的命令和演示模型可以用于任何types的用户界面。

更进一步,上面的“控制器”是非常通用的。 UI控件只需要知道要调用的命令的名称 – 它们(或控制器)不需要了解如何创build该命令或该命令需要哪些数据。 这是真正的优势。

例如,您可以保存要在Map中执行的命令的名称。 每当组件被“触发”(通常是一个actionPerformed),控制器就会查找命令名,实例化它,调用execute,并将它压入undo栈(如果使用的话)。

有一些select:

您可以通过属性或构造函数传递参数。

其他选项可能是:

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

并将所有的命令参数封装在一个值对象中。

在创build命令对象时传递人员:

 ICommand command = new DeletePersonCommand(person); 

所以当你执行命令时,它已经知道它需要知道的一切。

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

我的实现是(使用Juanma提出的ICommand):

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

IPersonService可以是一个IPersonRepository,它取决于你的命令是什么“层”。

在构造函数中并存储为字段。

您还将最终使您的ICommands可序列化为撤消堆栈或文件持久性。

在这种情况下,我们用Command对象做的事情就是创build一个基本上是地图的Context对象。 该映射包含名称值对,其中键是常量,值是Command实现使用的参数。 特别有用的,如果你有一个命令链,其中后来的命令依赖于从早期的命令上下文更改。

所以实际的方法变成了

 void execute(Context ctx); 

基于C#/ WPF中的模式,ICommand接口(System.Windows.Input.ICommand)被定义为将对象作为Execute上的参数,以及CanExecute方法。

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

这使您可以将您的命令定义为静态公共字段,该字段是实现ICommand的自定义命令对象的实例。

 public static ICommand DeleteCommand = new DeleteCommandInstance(); 

通过这种方式,相关的对象,在你的情况下,一个人,被传入时执行被调用。 Execute方法可以转换对象并调用Delete()方法。

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

您应该创build一个CommandArgs对象来包含您要使用的参数。 使用Command对象的构造函数注入CommandArgs对象。

DeletePersonCommand可以在其构造函数或方法中具有参数。 DeletePersonCommand将具有Execute()和Execute()可以检查的属性,Getter / Setter之前将会传递Execute()的调用。

我会添加任何必要的参数给DeletePersonCommand的构造DeletePersonCommand 。 然后,当调用Execute()时,会使用在构造时传递给对象的那些参数。

让“Person”实现某种IDeletable接口,然后使命令采取你的实体使用的任何基类或接口。 这样,你可以创build一个DeleteCommand,它试图将实体转换为一个IDeletable,如果这样的话,调用.Delete

 public class DeleteCommand : ICommand { public void Execute(Entity entity) { IDeletable del = entity as IDeletable; if (del != null) del.Delete(); } }