命令模式:如何将参数传递给命令?
我的问题与命令模式有关,其中我们有以下抽象(C# 代码):
public interface ICommand
{
void Execute();
}
让我们采用一个简单的具体命令,其目的是从我们的应用程序中删除一个实体。 例如,一个 Person
实例。
我将拥有一个实现 ICommand
的 DeletePersonCommand
。 该命令需要将要删除的Person
作为参数,以便在调用Execute
方法时将其删除。
管理参数化命令的最佳方法是什么? 在执行命令之前如何将参数传递给命令?
My question is related to the command pattern, where we have the following abstraction (C# code) :
public interface ICommand
{
void 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 ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
在本例中,我们对 Command 对象所做的就是创建一个 Context 对象,它本质上是一个地图。 该映射包含名称值对,其中键是常量,值是命令实现使用的参数。 如果您有一个命令链,其中后续命令依赖于早期命令的上下文更改,则特别有用。
所以实际的方法就变成了
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
创建命令对象时传递 person:
这样当您执行命令时,它已经知道它需要知道的一切。
Pass the person when you create the command object:
so that when you execute the command, it already knows everything that it needs to know.
在构造函数中并存储为字段。
您还需要最终使 ICommand 可序列化,以实现撤消堆栈或文件持久性。
In the constructor and stored as fields.
You will also want to eventually make your ICommands serializable for the undo stack or file persistence.
已经提到的 Blair Conrad 的代码(不知道如何标记他)工作得很好如果你知道实例化类时要删除哪个人并且他的方法就足够了。但是,如果你在按下按钮之前不知道要删除谁,您可以使用返回该人的方法引用来实例化该命令。
这样,当执行命令时,供应商会获取您要删除的人员,并在执行时执行此操作。 直到那时,该命令还没有关于要删除谁的信息。
关于供应商的有用链接。
注意:用java编写的代码。 具有 C# 知识的人可以对其进行调整。
Already mentioned code from Blair Conrad(don't know how to tag him) works perfectly fine if you know what person you want to delete when you instantiate the class and his method would suffice.But,if you don't know who you gonna delete until you press the button you can instantiate the command using a method reference that returns the person.
That way when the command is executed the supplier fetches the person you want to delete,doing so at the point of execution. Up until that time the command had no information of who to delete.
Usefull link on the supplier.
NOTE:code writen in java . Someone with c# knowledge can tune that.
基于 C#/WPF 中的模式,ICommand 接口 (System.Windows.Input.ICommand) 被定义为将对象作为 Execute 以及 CanExecute 方法的参数。
这允许您将命令定义为静态公共字段,它是实现 ICommand 的自定义命令对象的实例。
通过这种方式,相关对象(在您的例子中是一个人)会在调用execute时传入。 然后,Execute 方法可以转换该对象并调用Delete() 方法。
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.
This allows you to define your command as a static public field which is an instance of your custom command object that implements ICommand.
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.
您应该创建一个 CommandArgs 对象来包含要使用的参数。 使用 Command 对象的构造函数注入 CommandArgs 对象。
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.
DeletePersonCommand 可以在其构造函数或方法中包含参数。 DeletePersonCommand 将具有 Execute(),并且在执行中可以检查在调用 Execute() 之前由 Getter/Setter 传递的属性。
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().
我将向
DeletePersonCommand
的构造函数添加任何必要的参数。 然后,当调用 Execute() 时,将使用在构造时传递给对象的那些参数。I would add any necessary arguments to the constructor of
DeletePersonCommand
. Then, whenExecute()
is called, those parameters passed into the object at construction time are used.让“Person”实现某种 IDeletable 接口,然后使命令采用您的实体使用的任何基类或接口。 这样,您可以创建一个 DeleteCommand,它尝试将实体转换为 IDeletable,如果有效,则调用 .Delete
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
您需要通过构造函数或 setter 注入(或等效方法)将参数与命令对象关联起来。 也许是这样的:
You'll need to associate the parameters with the command object, either by constructor or setter injection (or equivalent). Perhaps something like this:
通过构造函数或设置器传递数据是可行的,但需要命令的创建者知道命令所需的数据......
“上下文”想法非常好,我正在研究利用它的(内部)框架一会儿回来。
如果您将控制器(与用户交互的 UI 组件、解释用户命令的 CLI、解释传入参数和会话数据的 Servlet 等)设置为提供对可用数据的命名访问,则命令可以直接请求它们想要的数据。
我真的很喜欢这样的设置所允许的分离。 按如下方式考虑分层:
如果“正确”地执行此操作,则相同的命令和表示模型可以用于任何类型的用户界面。
更进一步,上面的“控制器”是非常通用的。 UI 控件只需要知道它们将调用的命令的名称 - 它们(或控制器)不需要了解如何创建该命令或该命令包含哪些数据需要。 这才是真正的优势。
例如,您可以在映射中保存要执行的命令的名称。 每当组件被“触发”(通常是一个actionPerformed)时,控制器就会查找命令名称,实例化它,调用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:
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).
有一些选项:
您可以通过属性或构造函数传递参数。
其他选项可以是:
并将所有命令参数封装在值对象中。
There are some options:
You could pass parameters by properties or constructor.
Other option could be:
And encapsulate all command parameters in a value object.
我的实现是这样的(使用 Juanma 提出的 ICommand):
IPersonService 可以是 IPersonRepository,这取决于您的命令所在的“层”。
My implementation would be this (using the ICommand proposed by Juanma):
IPersonService could be an IPersonRepository, it depends in what "layer" your command is.