命令模式:如何将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(); } }