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

Gia*_*vas 8 .net c# asp.net design-patterns

我使用命令模式和自定义重试机制创建了一个回滚/重试机制,其中RetryCounttimeout threshold属性作为输入(如此处所述, 这是在C#中为同步/异步任务添加重试/回滚机制的最佳方法?).我也尝试了Polly框架,它很棒!

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

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

这些命令按某些类别分组,我必须针对不同的组和命令采取不同的回滚策略(基于结果).这里会有一些不同的政策!

重要提示:我想避免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(){...}
...
Run Code Online (Sandbox Code Playgroud)

另一个想法可能是观察者事件处理者,但问题是如何使用它们(?).或者只是使用命令的列表/堆栈/队列并检查该列表以采取下一步的决定(?):

  private List<ICommand> rollbackCommandsOfAllGroups;
  private List<ICommand> rollbackCommandsOfGroup1;
  private List<ICommand> rollbackCommandsOfGroup2;
...
Run Code Online (Sandbox Code Playgroud)

情景

最后,您可以考虑分为四(4)个类别的二十(20)个命令.

场景1

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

决定1

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

情景2

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

决定2

  • 回滚所有组的所有命令

我想引导我并帮助我使用C#中的CODE示例.

Joh*_*rog 9

我想,你需要像MultiCommand Pattern 这样的东西.它在HeadFirst Design Patterns一书中得到了很好的定义.

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

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

interface ICommand
    {
        bool Execute();

        void Rollback();

        void BatchRollback();
    }
Run Code Online (Sandbox Code Playgroud)

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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

注意,我们也使用了模板方法模式:基类的Execute()方法实现了命令执行和回滚的基本逻辑,而每个命令的特定操作将在子类的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
    }
Run Code Online (Sandbox Code Playgroud)

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

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");
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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");
        }
    }
Run Code Online (Sandbox Code Playgroud)

让我们尝试使用所有这些员工: 场景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();
        }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我们创建了一些命令,将它们分组(组是Multicommands,可以拥有尽可能多的嵌套).

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

以下是测试的输出:

command 1 executed
command 2 executed
command 3 executed
failed command executed
failed command cancelled
command 3 canceled
command 2 canceled
command 1 canceled
Run Code Online (Sandbox Code Playgroud)

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

[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();
        }
Run Code Online (Sandbox Code Playgroud)

输出在这里:

command 1 executed
command 2 executed
failed command executed
failed command cancelled
command 1 canceled
Run Code Online (Sandbox Code Playgroud)

我希望它对你的情况有用......你可以在GitHub上找到这个例子.

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