在setter方法中进行验证:哪种方法更好?

4
我和我的朋友有争议。
他告诉我这段代码:
method SetBalance(balance) {
    if (balance > 0) {
        this.balance = balance;
        return true;
    }
    return false;
}

比这更好:
method SetBalance(balance) {
    if (balance < 0) {
        throw new InvalidArgumentException("Balance couldn't be negative")
    }
    this.balance = balance; 
}

我的问题是:“哪种验证方法更好?”为什么?
谢谢。

即使返回更好,我也会使用比bool更具描述性的东西。 - Giedrius
6个回答

6

啊。返回状态与异常。

我更喜欢抛出异常,因为你不能真正忽略一个异常。程序要么崩溃,要么你必须明确地捕获并处理它。

你可以忽略返回状态。

此外,现代编程中难道这不是异常存在的原因吗?处理异常情况(余额 <= 0, 不应发生的事情)。


我相信在一段时间之前有一个争论,即抛出异常的成本很高,因此如果可能避免异常,请使用其他方法。但我猜今天不再是这种情况了。 - Giedrius
@Giedrus,这是非常出名的口号。在这里,作者问到了如何纠正编码错误。异常完全有道理。 - Roman Saveljev
@Giedrius 我有所怀疑。你的参考资料是什么? - Luchian Grigore
@Giedrius 异常比返回状态更昂贵。 - Luchian Grigore
@Giedrius,你能发一下你用来进行性能分析的代码吗?它已经完全优化了吗? - Luchian Grigore
显示剩余6条评论

1

在设置器的情况下,开发人员不会期望从这些方法中返回任何值,因为他们认为这将自动处理设置的值。
如果出现异常,那么这将帮助他们了解到确实出了问题,并重新查看代码。
与其使用运行时异常,最好定义自己的异常,如InvalidBalanceException,并在签名中指定该方法将抛出此异常。这样可以避免在测试阶段出现意外情况,并在开发阶段就决定业务逻辑。


1

返回值很容易被忽略。在这里,你有明显的编码错误,所以会出现崩溃。我甚至会停止/段错误/停止程序 - 异常仍然可能被捕获。我们生活在“理想世界”中,但想象一下我们不那么幸运的同事 - 他们可能会选择禁用错误信号功能,无法处理根本原因(在此插入更复杂的错误场景)。当你不给客户以错误的方式做事时,编码变得更加容易。


0

我的个人观点是:两种方法都有其用途。这取决于情况为什么出现,它是否可以防止,客户可以做些什么来防止它。

服务器:

method SetBalance(int balance)
{
   // do something only if balance >= 0
}

客户:

myServer.SetBalance(balance);

情况1: 这种情况只会因为服务器或客户端中的某个错误而出现。抛出异常,让负责方修复其代码。

情况2: 从某个外部依赖项接收到了错误的输入。客户端可以轻松地检查前提条件。如果客户端对此不满意,请抛出异常并让客户端修复其代码。

if(balance>0)
  myServer.SetBalance(balance);
else
  //take appropriate action.

情况3: 从某些外部依赖项接收到了错误的输入。客户端无法轻松地检查前提条件。例如:这将要求客户端解析一个字符串,而这是服务器的工作。在这种情况下,服务器返回成功是有意义的:

bool succeeded = myServer.SetBalance(balance);
if(!succeeded)
  //take appropriate action.

在写下我的答案后,我注意到问题归结为:客户端不应该使用try-catch来调用SetBalance方法。(要么是一个bug,所以不要捕获异常,要么检查前置条件自己,或者检查返回值)
这里有一篇关于相关主题的好文章:http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx 编辑:Jojo提出了一个很好的观点。如果可能会失败,请将方法重命名为TrySetBalance()。

0

异常处理是面向对象编程中处理错误的首选方法,无论是运行时错误还是逻辑错误。为了证明异常处理的优势之一,可以举出这样一个论点:如果使用错误代码,函数的客户端可能会忘记检查错误代码,导致潜在的错误难以发现。而如果使用异常处理,即使未被捕获,它也会传播直到被处理。因此,面向对象编程纯粹主义者总是建议使用异常处理。


0
除了已经给出的答案之外,在名为“setFoo”的函数中返回布尔值非常具有误导性。如果您将布尔值翻译成是/否,那么oop中返回布尔值的函数应该可读作一个问题,其答案为是/否,例如isBalanceSet。
在与同事讨论时,我们认为普通setter的唯一有效返回值是类本身,以用于流畅接口。
关于您的问题,如果类实际上自己验证其属性,则抛出异常是更好的解决方案;)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接