使用命令和工厂设计模式来执行排队作业

2023-11-24

我有一个在数据库中排队的作业列表,我需要从数据库中读取这些作业并使用线程并行执行它们,并且我有一个命令类列表来执行每个作业,所有这些作业都实现了通用接口(命令模式)。但是当我从数据库检索待处理的作业时,我需要为每个作业实例化正确的命令对象,如下所示(在工厂类中)

ICommand command;
switch (jobCode)
{
  case "A":
     command = new CommandA();
     break;
  case "B":
     command = new CommandB();
     break;
  case "C":
     command = new CommandC();
     break;
}

command.Execute();

有没有更好的方法来创建正确的命令对象而不使用像上面这样的大 switch 语句?或者是否有其他模式来执行排队作业?

解决方案:这样解决(基于所选答案)。这将执行命令对象的延迟实例化。

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();

大多数 C# 命令模式实现或多或少与 Java 实现相同。这些实现通常使用 ICommand 接口:

public interface ICommand
{
    void Execute();
}

然后所有命令类都被迫实现该接口。我对此解决方案没有任何问题,但就我个人而言,我不喜欢创建太多的类,我更喜欢使用 .NET 委托(Java 中没有委托)。如果只需要一个方法引用,则 Action 委托通常可以解决问题:

public class Prog
{
    public Prog()
    {
        var factory = new CommandFactory();
        factory.Register("A", () => new A().DoA);            
        factory.Register("B", () => new B().DoB);
        factory.Register("C", DoStuff);

        factory.Execute("A");
    }

  public static void DoStuff()
    {
    }
}

public class CommandFactory
{
    private readonly IDictionary<string, Action> _commands;       

    public void Register(string commandName, Action action)
    {
    _commands.Add(commandName, action); 
    }

    public Action GetCommand(string commandName)
    {
        _commands[commandName];
    }

    public void Execute(string commandName)
    {
        GetCommand(commandName)();
    }
}
public class A
{
    public void DoA()
    {
    }
}

public class B
{
    public void DoB()
    {
    }
}

如果您的命令界面需要不止一种方法,例如:

public interface ICommand
{
    void Execute();
    void Undo();
}

您可以使用这样的包装类:

public class Command
{
    public Command(Action execute, Action undo)
    {
        Execute = execute;
        Undo = undo;
    }

    public Action Execute { get; protected set; }
    public Action Undo { get; protected set; }
}

或(哪一个并不重要)

public class Command 
{
    private readonly Action _execute;
    private readonly Action _undo;

    public Command(Action execute, Action undo)
    {
        _execute = execute;
        _undo = undo;
    }

    public void Execute()
    {
        _execute();
    }

    public void Undo()
    { 
        _undo();
    }
}

(如果您已经有旧的东西使用它,这个甚至可以实现 ICommand。如果您使用该接口,工厂应该使用该接口而不是 Command 类)

使用这样的包装器,您不必被迫为您想要支持的每个操作创建一个命令类。以下示例演示了如何使用包装类:

public class Prog2
{
    public Prog2()
    {
        var factory = new CommandFactory2();
        factory.Register("A", new Lazy<Command>(
            ()=>
                {
                    var a = new A();
                    return new Command(a.DoA, a.UndoA);
                }));

        factory.Register("B", new Lazy<Command>(
           () =>
           {
               var c = new B();
               return new Command(c.DoB, c.DoB);
           }));

        factory.Register("C", new Lazy<Command>(
            () => new Command(DoStuff, UndoStuff)));

        factory.Execute("A");
    }

    public static void DoStuff()
    {
    }

    public static void UndoStuff()
    {
    }
}

public class CommandFactory2
{
    private readonly IDictionary<string, Lazy<Command>> _commands;

    public void Register(string commandName, Lazy<Command> lazyCommand)
    {
        _commands.Add(commandName, lazyCommand);
    }

    public void Register(string commandName, Action execute, Action undo)
    {
        _commands.Add(commandName, new Lazy<Command>(() => new Command(execute, undo)));
    }

    public Command GetCommand(string commandName)
    {
        return _commands[commandName].Value;
    }

    public void Execute(string commandName)
    {
        GetCommand(commandName).Execute();
    }

    public void Undo(string commandName)
    {
        GetCommand(commandName).Undo();
    }
}


public class A
{
    public void DoA()
    {
    }

    public void UndoA()
    {
    }
}

public class B
{
    public void DoB()
    {
    }

    public void UndoB()
    {
    }
}

正如您所看到的,即使您有多个方法(执行、撤消等),也无需实现该接口。请注意,执行和撤消方法可能属于不同的类。您可以自由地以更自然的方式构建代码,并且仍然可以使用命令模式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用命令和工厂设计模式来执行排队作业 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使

随机推荐

  • 在Java中,如何从派生类中的重写方法调用基类的方法?

    我有两个Java类 B 它扩展了另一个类A 如下 class A public void myMethod class B extends A public void myMethod Another code 我想致电A myMethod
  • 用户代理可以在其请求中设置大于零的 max-age 吗?

    我有一个疑问max age读取 Http 缓存后的行为rfc 设想 用户代理 GET foo 源服务器响应头 cache control max age 120 服务器告诉用户代理所请求的资源应在 2 分钟后重新验证 1分零几秒后 用户代理
  • 将列和行大小重置为默认值

    我正在构建一个脚本 通过自定义菜单项访问 其中还将包含一些样式 例如设置背景颜色 更改列宽 行高以及插入大量内容 现在我想实现一个 重置 功能 setall单元格恢复为默认的空 Google 表格的样子 包括所有内容 我找到了clear f
  • UISearchController - 警告尝试加载视图控制器的视图

    我收到以下错误 尝试加载视图控制器的视图 不允许解除分配并可能导致未定义的行为 尝试了以下解决方案 但对我不起作用正在解除分配时尝试加载视图控制器的视图 UISearchController 链接中提供了演示项目 点击主控制器中的添加按钮
  • Google App Engine 模块间通信授权

    In the 谷歌文档 it says 您可以将任何手动或基本扩展模块配置为接受来自应用程序中其他模块的请求 方法是将其处理程序限制为仅允许管理员帐户 并在模块的配置文件中为适当的处理程序指定 login admin 实施此限制后 来自应用
  • “控制器”是命名空间,但像类型一样使用

    当我创建新控制器时总是抛出错误 Controller 是命名空间 但像类型一样使用 我不知道如何修复它 我已经安装了该包 在此输入图像描述 将文件夹名称更改为 Controllers 将命名空间更改为 Controllers 因此您的代码应
  • 未复制引用的项目依赖项 DLL

    我的项目解决方案目前有三个项目 我的项目 这是我的主要启动项目 使用 NET Framework 4 7 WPF 特定于 UI 我的项目 核心 类库 NET Standard 2 0 保存模型以及所有 幕后 数据 我的项目 关系 类库 NE
  • SwiftUI 更新核心数据对象更改视图

    我遇到的问题是 当我从工作表视图更新核心数据资产对象时 更改不会反映在 AssetListView 的 UI 中 请注意 从工作表视图插入新对象does刷新 AssetListView 的 UI 删除工作表视图中的对象也刷新AssetLis
  • 在jsp中显示日期差异

    我在数据库中有一个日期字段 仅存储日期而不存储时间 现在我想知道在 jsp 页面中显示当前日期和我的日期字段的天数差异 所以我应该喜欢 databaseDate 2012 11 30 currentDate 2012 11 27 3 day
  • MS Access 编程概述 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 我是一名 Java EE 开发人员 刚刚有人联系我 希望我为他的业务提供一个可以与他们的 MS Access 后端 集成的应用程序的报价 我希望发布
  • 为什么 XML 中的节点顺序很重要?

    我最近一直在处理一个 API 它要求 XML 文档的节点按特定顺序排列 我想知道为什么他们觉得有必要强制执行这一点 而我完全找不到理由让事情变成这样 例如 这是正确的 xml 大大简化
  • 将 exe 从一个项目复制到另一个项目的调试输出目录

    我有两个项目 ProjOne exe 和 ProjTwo exe 我想构建 ProjOne exe 它知道它依赖于 ProjTwo exe 因此它在构建 ProjOne exe 时会复制 ProjTwo exe 我还有一个 ProjThre
  • jQuery:当div变得可见时如何为其绑定事件?

    我有一个 div 元素 div Tab data div 当这个 div 变得可见时如何绑定自定义事件 获取display block 而且我想在这个 div 变得不可见时绑定一个事件 获取display none 我想用 jQuery 来
  • 如何将列添加到架构的开头?

    Dataset withColumn 似乎将该列附加到架构的末尾 如何将列添加到架构的开头 Use select带通配符 df select new column col
  • FragmentActivity 与 ViewPager:方向更改时崩溃

    我在FragmentActivity中使用了ViewPager 当方向改变时我会崩溃 Override protected void onCreate Bundle savedInstanceState super onCreate sav
  • ShaderTextureLod参数值?

    LOD参数取什么值纹理洛德 我找到的规范根本没有提到这一点 是百分比还是带百分比的指数值 如果是后者 有没有办法获取纹理的 mipmap 数量 以便我能够使用百分比 LOD参数指定 mipmap 级别 四舍五入到最接近的整数 请记住 Ope
  • Docker 和 XDebug 不读取断点 VSCode

    过去 6 个月 我一直在 MAC 上使用 XDebug 和 PHP 7 0 版本 对 Docker 容器进行远程调试 我正在运行旧版本的 docker 它使用 VirtualBox 来为 docker 建立虚拟机 一切正常 我最近将 doc
  • 无法解决 PyCaret 的导入错误

    我试图通过在 anaconda python 3 8 中创建环境来安装 pycaret 一切都很好 除了当我试图从pycaret classification import 尽管我已经安装了所有依赖项 但我还是显示错误 ImportErro
  • 列出用户定义的变量,python

    我正在尝试迭代 python 脚本中设置的变量 我遇到了以下情况 枚举或列出 此处您最喜欢的语言 程序中的所有变量 在第一个例子中 us bin python foo1 Hello world foo2 bar foo3 1 a 2 b f
  • 使用命令和工厂设计模式来执行排队作业

    我有一个在数据库中排队的作业列表 我需要从数据库中读取这些作业并使用线程并行执行它们 并且我有一个命令类列表来执行每个作业 所有这些作业都实现了通用接口 命令模式 但是当我从数据库检索待处理的作业时 我需要为每个作业实例化正确的命令对象 如