使用命令和工厂设计模式来执行排队作业
我有一个在数据库中排队的作业列表,我需要从数据库中读取这些作业并使用线程并行执行它们,并且我有一个命令类列表来执行每个作业,所有这些作业都实现了通用接口(命令模式)。但是当我从数据库中检索待处理的作业时,我需要为每个作业实例化正确的命令对象,如下所示(在工厂类中)
ICommand command;
switch (jobCode)
{
case "A":
command = new CommandA();
break;
case "B":
command = new CommandB();
break;
case "C":
command = new CommandC();
break;
}
command.Execute();
是否有更好的方法来创建正确的命令对象,而不使用像这样的大开关语句多于?或者是否有其他模式来执行排队作业?
解决方案:这样解决(基于所选答案)。这将执行命令对象的延迟实例化。
public class CommandFactory
{
private readonly IDictionary<string, Func<ICommand>> _commands;
public CommandFactory()
{
_commands = new Dictionary<string, Func<ICommand>>
{
{"A", () => new CommandA()},
{"B", () => new CommandB()},
{"C", () => new CommandC()}
};
}
public ICommand GetCommand(string jobKey)
{
Func<ICommand> command;
_commands.TryGetValue(jobKey.ToUpper(), out command);
return command();
}
}
Client:
var factory = new CommandFactory();
var command = factory.GetCommand(jobKey);
command.Execute();
I have a list of jobs queued in the database which I need to read from database and execute them in parallel using threading and I have a list of command classes to execute each of those jobs all implementing a common interface (command pattern). but when I retrieve the pending jobs from the database, I will need to instantiate the right command object for each job something like this (in a factory class)
ICommand command;
switch (jobCode)
{
case "A":
command = new CommandA();
break;
case "B":
command = new CommandB();
break;
case "C":
command = new CommandC();
break;
}
command.Execute();
Is there a better way to create the right command object without using a big switch statement like above? OR is there any other pattern for executing the queued jobs?
Solution: solved like this (based on the selected answer). This will do lazy instantiation of the command objects.
public class CommandFactory
{
private readonly IDictionary<string, Func<ICommand>> _commands;
public CommandFactory()
{
_commands = new Dictionary<string, Func<ICommand>>
{
{"A", () => new CommandA()},
{"B", () => new CommandB()},
{"C", () => new CommandC()}
};
}
public ICommand GetCommand(string jobKey)
{
Func<ICommand> command;
_commands.TryGetValue(jobKey.ToUpper(), out command);
return command();
}
}
Client:
var factory = new CommandFactory();
var command = factory.GetCommand(jobKey);
command.Execute();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
大多数 C# 命令模式实现或多或少与 Java 实现相同。这些实现通常使用 ICommand 接口:
然后所有命令类都被迫实现该接口。我对此解决方案没有任何问题,但就我个人而言,我不喜欢创建太多的类,我更喜欢使用 .NET 委托(Java 中没有委托)。如果只需要一个方法引用,操作委托通常可以解决问题:
如果您的命令接口需要多个方法,例如:
您可以使用这样的包装类:
或(无论是哪一个)
(这个甚至可以实现ICommand(如果您已经有旧的东西使用它)如果您使用该接口,工厂应该使用该接口而不是 Command 类)
使用这样的包装器,您不必为您想要支持的每个操作创建一个命令类。下面的示例演示了如何使用包装类:
如您所见,即使您有多个方法(执行、撤消等),也无需实现该接口。请注意,执行和撤消方法可能属于不同的类。您可以自由地以更自然的方式构建代码,并且仍然可以使用命令模式。
Most C# command pattern implementations more or less the same as a Java implementation. These implementations usually use a ICommand interface:
and then all command classes are forced to implement the interface. I have no issues with this solution, but personally I don't like creating too many classes and I prefer to use .NET delegates instead (there are no delegates in Java). The Action delegate usually does the trick if only need one method reference:
If your command interface needs more than one methods like:
You can use a wrapper class like this:
or (it doesn't matter which one)
(this one may even implement ICommand if you have legacy stuff using it already. If you use the interface the factory should use the interface instead of the Command class)
With a wrapper like this you are not forced to create a command class for each action you want to support. The following example demonstrates how you can use the wrapper class:
As you can see there is no need to implement the interface even if you have more than one method (Execute, Undo, etc). Please note that the Execute and Undo methods may belong to different classes. You are free to structure your code the way it feels more natural and still can use the command pattern.
您可以使用
Dictionary
将字母/字符映射到相关的ICommand
实现。类似于:使用它,您可以注册命令类型并将它们映射到基于字符串的键,并允许它们更通用地实例化和执行。您可以通过仅在首次使用命令类型时实例化它们来提高性能。
编辑
为了回答您的评论,要仅在执行时实例化,您可以执行以下操作:
You could use a
Dictionary
to map the letter/character to the relevantICommand
implementation. Something like:Using this, you can register command types and map them to
string
-based keys and allow them to be instantiated and executed more generically. You could improve performance by only instantiating the command types when they are first used.EDIT
In answer to your comment, to instantiate only when executing, you could do something like:
您可以考虑要求您的工作提供它自己的 ICommand:
然后,您可以执行以下操作,而不是打开 jobCode:
You could consider asking your job to provide it's own ICommand:
Then rather than switching on the jobCode, you could just do: