Logic 顺序逻辑与可读性

Logic 顺序逻辑与可读性,logic,Logic,这是一个抽象的问题,没有真正的代码(也许也不是最好的伪代码),所以希望它有足够的意义,不会被扼杀。但这是一个反复出现在我面前的问题,因为我正在从事的项目是一个非常线性的过程,依赖于以前的条件。所以 给定一系列逻辑任务,每个任务都依赖于前一个任务,我尝试了两种方法来构造代码。 一个依赖于procedure变量,如下所示 Proceed = True If Task1 Not Successful Then Proceed = False End If If Proceed Then

这是一个抽象的问题,没有真正的代码(也许也不是最好的伪代码),所以希望它有足够的意义,不会被扼杀。但这是一个反复出现在我面前的问题,因为我正在从事的项目是一个非常线性的过程,依赖于以前的条件。所以

给定一系列逻辑任务,每个任务都依赖于前一个任务,我尝试了两种方法来构造代码。 一个依赖于
procedure
变量,如下所示

Proceed = True

If Task1 Not Successful Then
    Proceed = False
End If

If Proceed Then 
    If Task2 Not Successful Then 
        Proceed = False
    End If
End If
等等

但我在许多地方读到评论,大意是这种运行的变量方法并不理想。所以,我也可以选择

If Task1 Succcesful Then 
    If Task2 Successful
       Then Etc
    Else
        Error Condition
    End If
Else
    Error Condition
End If
在我看来,前者更具可读性,逻辑也很明显。而且,当序列中的任务数量变大(超过3个或真的)时,嵌套的Ifs就变得非常笨拙。 那么,我的问题是,不使用第一种方法的原因是什么? 还有没有更好的方法来构造第二个示例中的逻辑以提高可读性? 还是有第三种方法可以解决前者的问题(不管是什么),以及后者的可读性问题?
或者,当一个人确实有一系列顺序相关的任务时,第一种方法真的很好吗?

这取决于你手头的情况。没有任何进一步的细节,并且坚持使用与原始块完全相同的代码,我将从避免不必要的嵌套开始:

Proceed = False;

if Task1 successful and Task2 successful Then
    Proceed = True
end if
在大多数语言中,您可以直接将布尔值放入变量中

Proceed = task1 successful and task2 successful
如果您确实希望避免和,那么可能是这样:

Proceed = True;

If Task1 not successful then
    Proceed = False
Else if Task2 not successful then
    Proceed = False
Else if Task3 not successful then
    Proceed = False
End if
到目前为止,在所有情况下都避免嵌套。为了可读性,这一点很重要

除此之外,您的候补者还有两个变化。首先是“procedure”变量被完全删除。我同意这一点。您的原始代码的读者必须克服的是:

初始化x。。。现在,如果x,那么准备好y。。。好了,现在开始做

如果可以将此更改为:

如果x那么做y

这在概念上更容易

因此,我会:

If Task1 successful and Task2 successful and Task3 successful then
    Do your thing
End if


第二个区别是您将其置于“错误条件”中。特别是,你提到了“错误”。如果您正在阅读的文档说您应该处理错误(例如停止执行并打印错误消息),那么这是正确的。不过,如果有机会,您应该在使用if/then语句之前处理它们,例如在Task1过程中。这不仅简化了if/then语句,而且对程序员来说也是一种更好的体验,因为任何像样的IDE都会导致他们失败,最好是在失败出现时立即处理,这样开发人员就不会有很长的路要走,以查看最终的源代码是什么

两者都很常见。第一种方法在使用某些连贯的API时尤其常见,这些API需要在一个序列中调用多个方法:

API_THING *thing = NULL;
API_RESULT result = CreateThing(&thing, ...);
if (API_OK == result) result = InitializeThing(&thing, ...);
if (API_OK == result) result = DoThingToThing(&thing, ...);
// ...
if (thing)
{
    ReleaseThing(&thing, ...);
    thing = NULL;
}
如果不需要嵌套超过2-3层深(特别是在处理两种情况时),则另一种情况很常见:

另一个未被建议的是
goto
和/或例外:

API_THING *thing = NULL;
if (API_OK != CreateThing(&thing, ...)) goto CLEANUP;
if (API_OK != InitializeThing(&thing, ...)) goto CLEANUP;
if (API_OK != DoThingToThing(&thing, ...)) goto CLEANUP;
//...
CLEANUP:
if (thing)
{
    ReleaseThing(&thing, ...);
    thing = NULL;
}
如果使用异常,您可能会像上面的
goto
示例一样,在每一行抛出异常,或者您可能会将API封装在抛出以下异常的方法中:

void DoCreateThing(API_THING **thing, ...)
{
    if (API_OK != CreateThing(thing, ...))
        throw new ApiException("CreateThing Failed!");
}

//...

API_THING *thing = NULL;
try
{
    DoCreateThing(&thing, ...);
}
catch (ApiException e)
{
   // ...
}
// ...
finally
{
    if (thing)
    {
        ReleaseThing(&thing, ...);
        thing = NULL;
    }
}
振作起来:如果您的编程是正确的,那么您在这里所做的任何决定都不会像您如何从您的高级架构中封装这些行为那样重要

void DoCreateThing(API_THING **thing, ...)
{
    if (API_OK != CreateThing(thing, ...))
        throw new ApiException("CreateThing Failed!");
}

//...

API_THING *thing = NULL;
try
{
    DoCreateThing(&thing, ...);
}
catch (ApiException e)
{
   // ...
}
// ...
finally
{
    if (thing)
    {
        ReleaseThing(&thing, ...);
        thing = NULL;
    }
}