我使用命令模式创建了一个回滚/重试机制,并使用RetryCount
和timeout threshold
属性作为输入自定义重试机制(如此处所述) Which is the best way to add a retry/rollback mechanism for sync/async tasks in C#?)。我也尝试了 Polly框架而且非常棒!
现在,我想将它们包装在一个抽象中。我可以将其描述为命令计划机制或基于命令的决策机制。
所以,基于命令结果的不同组合,我必须决定哪些已完成的命令将被还原,哪些不能(我想提供按下ReTry按钮的功能,而某些命令不应该是&#39 ;恢复原状。)
这些命令按某些类别分组,我必须针对不同的组和命令采取不同的回滚策略(基于结果)。这里会有一些不同的政策!
重要提示:我想避免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
决定1
场景2
决定2
我想引导我并帮助我使用C#中的 CODE 示例。
答案 0 :(得分:9)
我想,你需要像 MultiCommand 模式这样的东西。它在HeadFirst Design Patterns书中得到了很好的定义。
我创建了草稿设计,允许以灵活的方式管理命令。这不是最终决定,只是一个可能用于进一步设计的粗略想法......所以,我们走了:
首先,我们将为所有命令创建一个接口:
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()方法实现了命令执行和回滚的基本逻辑, 而每个命令的具体行动将在子类中实施。 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 相同的方式实现了 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");
}
}
让我们尝试使用所有这些员工: 场景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();
}
正如您所看到的,我们创建了一些命令,将它们分组(组是 Multicommands ,它们可以拥有尽可能多的嵌套)。
然后,我们将 group1 和 group2 推送到变量组以使用所有命令,例如一个。我们还推进了 Command3 和 FailCommand 的构造函数 如果出现问题,应该回滚的命令列表。在示例中,我们的 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
场景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();
}
输出在这里:
command 1 executed
command 2 executed
failed command executed
failed command cancelled
command 1 canceled
我希望它对你的情况有用...... 您可以在GitHub上找到此示例。
在最近的提交中,您可以找到更灵活的此方法版本