c# - 如何在C#中创建基于多命令结果组合的策略决策机制

标签 c# asp.net .net design-patterns

我已经使用 命令模式 创建了回滚/重试机制,并使用 RetryCounttimeout threshold 属性创建了自定义重试机制输入(如此处所述 Which is the best way to add a retry/rollback mechanism for sync/async tasks in C#? )。我还尝试了 Polly 框架,它很棒!

现在,我想将它们包装在一个抽象中。我可以将其描述为命令计划机制或基于命令的决策机制。

因此,根据命令结果的不同组合,我必须决定哪些已完成的命令将被还原,哪些不会(我想提供按下重试按钮的功能,而一些命令不应该被还原)。

这些命令被分组在一些类别中,我必须对不同的组和命令(基于结果)采取不同的回滚策略。这里会发生某种不同的政策!

重要:我想避免 IF/ELSE 等。也许 责任链模式 会帮助我,但我不知道我知道,我真的需要帮助:

//Pseudo-code...

CommandHandler actionManager1 = new Action1Manager();
CommandHandler actionManager2 = new Action2Manager();
CommandHandler actionManager2 = new Action3Manager();

actionManager1.SetNextObjManager(Action2Manager);
actionManager2.SetNextObjManager(Action3Manager);

actionManager1.ProcessAction(){...}
actionManager1.ProcessAction(){...}
...

另一个想法可能是observables事件处理程序,但问题是如何使用它们(?)。或者只是通过使用命令列表/堆栈/队列并检查该列表以做出下一步决定(?):

  private List<ICommand> rollbackCommandsOfAllGroups;
  private List<ICommand> rollbackCommandsOfGroup1;
  private List<ICommand> rollbackCommandsOfGroup2;
...

场景

最后,您可以将二十 (20) 个命令分为四 (4) 个类别。

场景一

  • 第 1 组命令 (5) 成功
  • 第 2 组命令 1 和 2 成功,但命令 3 失败 失败。命令 4 和 5 未执行
  • 第 3 组未执行
  • 第 4 组未执行

决定 1

  • 从第 2 组回滚命令 1 和 2 而不是整个第 1 组 命令

场景二

  • 第 1 组命令 (5) 成功
  • 第 2 组命令 (5) 成功
  • 第 3 组命令 (5) 成功
  • 第 4 组命令 1 - 4 成功命令 5 成功 失败

决定 2

  • 回滚所有组的所有命令

我想通过 C# 中的 CODE 示例指导和帮助我。

最佳答案

我想,您需要像 MultiCommand Pattern 这样的东西。在 HeadFirst Design Patterns 中定义得很好书。

我创建了一个草稿设计,它允许以灵活的方式管理命令。这不是最终决定,只是一个可能用于进一步设计的粗略想法……所以,我们开始吧:

首先,我们将为所有命令创建一个接口(interface):

interface ICommand
    {
        bool Execute();

        void Rollback();

        void BatchRollback();
    }

Rollback() 操作将取消命令本身,而 BatchRollback() 将取消所有依赖命令的堆栈。

其次,我们将创建一个带有简单Execute()Rollback() 方法实现的抽象BaseCommand 类:

abstract class BaseCommand : ICommand
    {
        private ICommand rollbackMultiCommand;

        #region constructors
        protected BaseCommand(MultiCommand rollbackMultiCommand = null)
        {
            this.rollbackMultiCommand = rollbackMultiCommand;
        }
        #endregion

        protected abstract bool ExecuteAction();

        public abstract void Rollback();

        public bool Execute()
        {
            if (!ExecuteAction())
            {
                BatchRollback();
                return false;
            }

            return true;
        }

        public void BatchRollback()
        {
            Rollback();

            if (rollbackMultiCommand != null)
                rollbackMultiCommand.Rollback();
        }
    }

请注意,我们也使用了模板方法模式:基类的 Execute() 方法实现命令执行和回滚的基本逻辑, 而每个命令的具体 Action 将在子类的ExecuteAction()方法中实现。

请查看 BaseCommand 构造函数:它接受 MultiCommand 类作为参数,它存储要回滚的命令列表,如果 执行过程中出现问题。

这是MultiCommand类的实现:

class MultiCommand : ICommand
    {
        private List<ICommand> rollbackCommands;

        private List<ICommand> commands;

        public MultiCommand(List<ICommand> commands, List<ICommand> rollbackCommands)
        {
            this.rollbackCommands = rollbackCommands;
            if (rollbackCommands != null)
                this.rollbackCommands.Reverse();
            this.commands = commands;
        }

        #region not implemented members
       // here other not implemented members of ICommand
       #endregion

        public bool Execute()
        {
            foreach (var command in commands)
            {
                if (!command.Execute())
                    return false;               
            }

            return true;
        }

        public void Rollback()
        {
            foreach (var rollbackCommand in rollbackCommands)
            {
                rollbackCommand.Rollback();
            }
        }
        #endregion
    }

好吧,我们的命令看起来像这样:

class Command1 : BaseCommand
    {
        public Command1(MultiCommand rollbackMultiCommand = null) : base(rollbackMultiCommand)
        {
        }

        protected override bool ExecuteAction()
        {
            Output("command 1 executed");
            return true;
        }

        public override void Rollback()
        {
            Output("command 1 canceled");
        }
    }

为简单起见,我以与 Command1 相同的方式实现了 Command2Command3Command4。然后,对于失败的命令模拟,我创建了这个:

class FailCommand : BaseCommand
    {
        public FailCommand(MultiCommand rollbackMultiCommand = null) : base(rollbackMultiCommand)
        {
        }

        protected override bool ExecuteAction()
        {
            Output("failed command executed");
            return false;
        }

        public override void Rollback()
        {
            Output("failed command cancelled");
        }
    }

让我们尝试使用所有这些人员: 场景 1:

[TestMethod]
        public void TestCommands()
        {
            var command1 = new Command1();
            var command2 = new Command2();
            var command3 = new Command3(new MultiCommand(null, new List<ICommand> { command1 }));
            var command4 = new FailCommand(new MultiCommand(null, new List<ICommand> { command1, command2, command3 }));

            var group1 = new MultiCommand(new List<ICommand>
            {
               command1,
               command2
            }, null);

            var group2 = new MultiCommand(new List<ICommand>
            {
               command3,
               command4
            }, null);

            var groups = new MultiCommand(new List<ICommand>
            {
                group1,
                group2
            }, null);

            groups.Execute();
        }

如您所见,我们创建了一些命令,将它们放入组中(组是多命令,可以嵌套任意多的嵌套)。

然后,我们将 group1group2 插入变量 group 以像一个一样使用所有命令。我们还插入了 Command3FailCommand 的构造函数 如果出现问题应该回滚的命令列表。在示例中,我们的 command3 执行良好,但 command4 失败。 因此,我们希望 command4command3command2command1 在失败后取消。

这是测试的输出:

command 1 executed
command 2 executed
command 3 executed
failed command executed
failed command cancelled
command 3 canceled
command 2 canceled
command 1 canceled

场景 2场景 1 几乎相同,但这里我们只想回滚 command3command1,如果 command3 失败:

[TestMethod]
        public void TestCommands2()
        {
            var command1 = new Command1();
            var command2 = new Command2();
            var command3 = new FailCommand(new MultiCommand(null, new List<ICommand> { command1 }));
            var command4 = new Command4(new MultiCommand(null, new List<ICommand> { command1, command2, command3 }));

            var group1 = new MultiCommand(new List<ICommand>
            {
               command1,
               command2
            }, null);

            var group2 = new MultiCommand(new List<ICommand>
            {
               command3,
               command4
            }, null);

            var groups = new MultiCommand(new List<ICommand>
            {
                group1,
                group2
            }, null);

            groups.Execute();
        }

输出在这里:

command 1 executed
command 2 executed
failed command executed
failed command cancelled
command 1 canceled

我希望它对你的情况有用...... 您可以在 GitHub 上找到此示例.

在最近的提交中,您可以找到这种方法的更灵活的版本

关于c# - 如何在C#中创建基于多命令结果组合的策略决策机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37613355/

相关文章:

c# - 如何使用 C# 自动右键单击系统托盘中的图标

.net - SaaS 模型的 ASP.NET 示例网站?

c# - 母版页 C# 3.0 中的 ASP.NET 网页全局化和本地化

c# - 如何解决 WPF 应用程序中的字体呈现问题?

c# - 将字符串格式化为 10 个字符

c# - Windows 10 上的时区偏移量为 "Egypt Standard Time"不正确

c# - 在 JSON 中解析 LINQ 答案

c# - ASP.NET MVC下无法使用C#设置和获取cookie

.net - 通过 serviceProxy 进行的第一个 WCF 调用的延迟是什么?

.net - 是否有用于管理 ASP.NET 应用程序的主题化 CSS 的库/工具?