结构化顺序处理的最佳设计模式

Best design pattern for structured sequential handling

我在维护一个项目时遇到了一些代码,我发现这些代码不必要地难以阅读,我希望重构它以提高可读性。

该功能是一长串需要按顺序执行的操作。仅当上一个操作成功时才​​应处理下一个操作。如果操作不成功,则需要设置相应的消息。 returned 类型是布尔值。 (成功true/false)。就像所有调用的动作的 return 类型一样。

基本上就是这样。

string m = String.Empty; // This is the (error)Message.
bool x = true; // By default the result is succesful.

x = a1();
if(x) {
    x = a2();
}
else {
    m = "message of failure a1";
    return x;
}

if(x) {
    x = a3();
}
else {
    m = "message of failure a2";
    return x;
}

//etcetera..etcetera...

if(x){
    m = "Success...";
}
else{
    m = "Failure...";
}

return x;

我的问题是:处理这种逻辑的更好结构/模式是什么?

主要目标是:

请记住,这是一连串按顺序执行的操作。 (数千行代码)

列出 action/message 对:

class Activity {
    public Func<bool> Action { get; set; }
    public String FailureMessage { get; set; }
}

Activity[] actionChain = new[] {
    new Activity { Action = A1, FaulureMessage = "a1 failed"}
,   new Activity { Action = A2, FaulureMessage = "a2 failed"}
,   new Activity { Action = A3, FaulureMessage = "a3 failed"}
};

A1..A3 是返回 bool 的无参数方法。如果您的某些操作需要参数,您可以为它们使用 lambda 表达式:

Activity[] actionChain = new[] {
    ...
,   new Activity { Action = () => An(arg1, arg2), FaulureMessage = "aN failed"}
,   ...
};

现在你可以遍历对,并在第一次失败时停止:

foreach (var a in actionChain) {
    if (!a.Action()) {
        m = a.FailureMessage;
        return false;
    }
}
m = "Success";
return true;

@dasblinkenlight 更快...但是使用 yield 而不是数组的类似解决方案:

public string Evaluate()
{
    foreach (var customAction in EnumerateActions())
    {
        if (!customAction.Execute())
            return customAction.Error;
    }
    return "Success...";
}

public IEnumerable<CustomAction> EnumerateActions()
{
    yield return new CustomAction(a1, "Error for A1");
    yield return new CustomAction(a2, "Error for A2");
    ...
}

public class CustomAction
{
    public Func<bool> Execute { get; }
    public string Error { get; }
    public CustomAction(Func<bool> action, string error)
    {
        Execute = action;
        Error = error;
    }
}