你正在设计一种方法。它有一个目的,这就是你首先设计它的原因。调用者使用你的方法并且方法失败,但是,并且看,尽管如此,仍然实现了延长方法存在的最终目的 - 由于你无法控制的外部环境或某种魔法,你选择。您是否会将这种情况报告给调用者失败或成功?
让我们选择一个简单的例子。你正在写一个DeleteFile
函数。它需要一个文件路径并删除该文件。有人调用此函数,提供路径。该函数查找文件,但它不存在。这不是权限问题或其他什么,文件真的丢失了。也许另一个进程在一个微秒前删除了它,也许它根本就不存在。该函数无法执行其任务,因此它必须报告失败...但是用户调用此函数的唯一原因是确保文件不存在,并且,瞧,它没有,所以它是一个成功。
我期待的回答就像“只是在你的回报价值中更加冗长”,我很乐意将详细结果作为补充信息返回,但是你会回答什么(和为什么)作为功能的主要成功标志,成功还是失败?使用BUT_DOES_NOT_EXIST_ANYWAY的附加标志会是FALSE,还是BUT_THANK_SOMEONE_ELSE标志为TRUE?
我一般都在询问情况,包括方法没有参数,或者由于其他原因无法以错误的方式调用它。
答案 0 :(得分:13)
当新程序员学习如何编写函数时,通常会引入术语前置条件和后置条件。前提条件是您的方法正常工作必须满足的假设。后置条件是保证您的方法在执行后对系统的状态做出的。
我认为调用deleteFile
方法时期望的合理前提是文件当前存在。如果不满足前提条件,该方法应失败,即使后置条件是以偶然的迂回方式实现的。
现在,如果您的方法被称为deleteFileIfExists
,那就是另一个故事。你没有对这种方法施加如此严格的先决条件。
答案 1 :(得分:7)
遵循最少惊喜的原则,并抛出异常。
我想到的方式是这样的:如果我正在编写代码并在我的代码中包含一个错误路径传递给DeleteFile函数的错误,一个路径如此不正确以至于它永远不存在,我希望DeleteFile能够扔,表示我做错了什么。
如果你想要,你可以创建一个接受名为ThrowOnFileNotExist或其他东西的参数的重载,如果设置为false,它就不会抛出这种情况。但我认为这将是罕见的异常情况。
答案 2 :(得分:4)
这就是例外情况。
抛出新的FileDoesNotExistException
答案 3 :(得分:3)
如果你打算失败并成功这样做,你做了什么?
我认为由客户决定做什么。如果要求您的函数删除不存在的文件,则抛出异常。然后,客户端可以捕获该异常,并确定该文件是否不存在或是否已成功删除,最终结果是相同的,并且可以正常进行。
或者,如果丢失的文件是预期的可能性,即非常例,则可以返回调用者可以忽略的失败状态:)这再次将决定留给客户端。
在任何一种情况下,如果你遵循一个函数应该做一件事并且做得好的原则,客户端可以以任何适当的方式将函数调用串联起来用于手头的任务,并且成功或失败变得更加精细
如果功能未成功完成,则不应该返回成功。如果最终结果巧合地相同则无关紧要。这就是疯狂。
答案 4 :(得分:1)
你的例子对于三元布尔是一个完美的例子:True/False/FileNotFound。
enum Bool
{
True,
False,
FileNotFound
};
<强>更新强>
所有人都开玩笑。如果该方法无法执行它的功能,那么它应该具有适合于该情况的返回代码(或抛出异常)。如果最终结果相同,则与方法无关;虽然它可能是该方法的调用者。
我更愿意避免抛出异常,而是维护返回代码。 IMHO异常类型存在于代码无法处理的情况。你的示例方法足够小,只需返回False即可。由调用代码决定原因。
有很多原因导致像DeleteFile这样的简单方法失败。文件不存在,您没有安全权限,文件被锁定,文件系统被延迟等等。每个文件都应该有自己特定的返回失败代码。
然后由调用代码决定“哦文件不存在,没关系”。或者,“你是什么意思我没有权利?!?中止!!”
点是:除非方法可以实际执行,否则不返回true。
答案 5 :(得分:0)
该函数应抛出异常(或返回失败值,无论如何)。但是,用户应该会看到成功。
IOW,调用该函数的程序员应该知道真相。但是用户界面向用户呈现的内容取决于整体功能,我想是目标用户。
采取你的“删除文件”示例 - 在正常情况下,我希望你的应用程序只是从列表中删除文件,或者其他什么,然后继续 - 让用户看到文件已被删除;他们可能并不关心它是如何发生的。
(“在正常情况下”,因为在某些应用程序中,它可能很重要。)