一般功能问题(C++/Java/C#)

Yip*_*Yay 7 c# c++ java function prerequisites

这个问题可能与语言无关,但我将专注于指定的语言.

在处理一些遗留代码的过程中,我经常看到函数的例子,(在我看来,显然)在它们内部做了太多的工作.我说的不是5000 LoC怪物,而是关于在其中实施先行检查的功能.

这是一个小例子:

void WorriedFunction(...) {
   // Of course, this is a bit exaggerated, but I guess this helps
   // to understand the idea.
   if (argument1 != null) return;
   if (argument2 + argument3 < 0) return;
   if (stateManager.currentlyDrawing()) return;

   // Actual function implementation starts here.

   // do_what_the_function_is_used_for
}
Run Code Online (Sandbox Code Playgroud)

现在,当调用这种函数时,调用者不必担心要满足的所有先决条件,并且可以简单地说:

// Call the function.
WorriedFunction(...);
Run Code Online (Sandbox Code Playgroud)

现在 - 应该如何处理以下问题?

就像,一般来说 - 如果此功能仅执行所要求的操作并将"先决条件检查"移至呼叫方:

if (argument1 != null && argument2 + argument3 < 0 && ...) {
   // Now all the checks inside can be removed.
   NotWorriedFunction();
}
Run Code Online (Sandbox Code Playgroud)

或者 - 它是否应该根据每个先决条件不匹配抛出异常?

if (argument1 != null) throw NullArgumentException;
Run Code Online (Sandbox Code Playgroud)

我不确定这个问题是否可以概括,但我仍然希望你对此有所了解 - 可能有些东西我可以重新思考.

如果您有其他解决方案,请随时告诉我他们:)

谢谢.

Ira*_*ter 6

每个函数/方法/代码块都应该有一个前置条件,它是设计工作的精确环境,后置条件,函数返回时的世界状态.这些帮助您的程序员了解您的意图.

根据定义,如果前提条件为假,则预期代码不起作用,如果后置条件为假,则认为代码错误.

无论您是将它们写在脑海中,在设计文档中的纸上,在评论中,还是在实际的代码检查中,都是一种品味问题.

但是,如果将前置条件和后置条件编码为显式检查,则实际问题(长期)生活会更容易.如果您对此类检查进行编码,因为代码不能使用错误的前置条件,或者错误的后置条件,那么条件前和条件后检查应该导致程序报告错误的方式使其变得简单发现故障点.什么代码不应该只是"返回"没有做任何事情,正如你的例子所示,因为这意味着它已经以某种方式正确执行.(代码当然可以定义为在没有做任何事情的情况下退出,但如果是这种情况,那么前后条件应该反映这一点.)

显然,您可以使用if语句编写此类检查(您的示例非常接近):

if (!precondition) die("Precondition failure in WorriedFunction"); // die never comes back
Run Code Online (Sandbox Code Playgroud)

但是通常在代码中通过为称为断言的语言定义特殊函数/宏/语句来指示前置条件或后置条件的存在,并且这种特殊构造通常会导致程序中止并在断言时回溯是假的.

编写代码的方式如下:

void WorriedFunction(...)  
 {    assert(argument1 != null); // fail/abort if false [I think your example had the test backwards]
      assert(argument2 + argument3 >= 0);
      assert(!stateManager.currentlyDrawing());
      /* body of function goes here */ 
 }  
Run Code Online (Sandbox Code Playgroud)

复杂的功能可能愿意告诉他们的呼叫者某些情况已经失败.这是例外的真正目的.如果存在异常,从技术上讲后置条件应该说明"函数可能在条件xyz下以异常退出"的效果.