2009-10-30 140 views
3

即使在我的程序中没有可以合理输入错误数据的地方,我总是有习惯总是验证属性设置器是否对不良数据有效。我的质量保证人员不希望我抛出异常,除非我能解释他们会在何处发生。我应该验证所有属性吗?我可以指出这个标准吗?面向对象设计的问题 - 验证属性

例子:

public void setName(String newName){ 
    if (newName == null){ 
     throw new IllegalArgumentException("Name cannot be null"); 
    } 
    name = newName; 
} 

... 

//Only call to setName(String) 
t.setName("Jim"); 
+1

看起来您的质量检查人员没有针对这些支票投放分支获得单元测试覆盖率。你应该告诉他们停止懒惰,并且将其包含在测试中,因为它应该是。 – 2009-10-30 19:59:59

+0

单元测试?我们不需要单元测试......(我知道,我知道,但我不能改变一切......) – 2009-10-30 20:03:27

回答

4

你执行你的方法的前提条件,这是其合同的重要组成部分。这样做没有问题,它也可以作为自我记录代码(如果我阅读了你的方法代码,我立即明白我不应该传递给它的代码),尽管assert可能更适用于此。

1

你做的不错! 无论是setter还是函数 - 总是验证并抛出有意义的异常。你永远不知道什么时候需要它,你会...

0

这是一个折衷。这是编写,审查和维护的更多代码,但如果某个空名称能够通过,您可能会发现更快的问题。

我倾向于拥有它,因为最终你会发现你确实需要它。

我曾经有实用程序类来保持代码最小。因此,而不是

if (name == null) { throw new ... 

你可以有

Util.assertNotNull(name) 

那么Java添加断言的语言,你可以更直接地做到这一点。如果你想要关掉它。

2

在这些疯狂不可能的情况下,我个人更喜欢使用断言,只是为了避免难以阅读的代码,但要清楚的是假设在函数的算法正在取得进展。

但是,当然,这在很大程度上是一个主观判断的是,必须根据具体情况逐案基础上做出。你可以看到它(并且我已经看到它)完全失去控制 - 直到一个简单的函数变成了几乎从未评估为真的if语句的缠结。

0

在我看来做得很好。对于空值抛出IllegalArgumentException。对于其他类型的验证,您应该考虑使用与您的域对象相关的自定义例外层次结构。

1

一般来说,我不赞成这种做法。这并不是说执行验证是不好的,而是像简单的制定者那样,它往往比它在保护漏洞方面的价值更为混乱。我更喜欢使用单元测试来确保没有错误。

0

我不知道有任何文件标准说'验证所有用户输入',但这是一个非常好的主意。在该程序的当前版本中,可能无法使用无效数据访问此特定属性,但这不会阻止它在未来发生。维护过程中会发生各种有趣的事情。哎,你永远不知道什么时候有人会在不经过它之前验证数据的另一个应用程序中重用的类。

1

嗯,这是一段时间以来这个问题被张贴,但我想给一个不同的角度对这个话题。

使用你发布的具体例子,恕我直言,你应该做验证,但以不同的方式。

实现验证的关键在于问题本身。想想看:你在处理的是名字,而不是字符串。 字符串是非空名称。我们还可以考虑使字符串成为名称的其他特征:不能为空也不能包含空格。

假设您需要添加这些验证规则:如果您坚持使用您的方法,您会像@SingleShot所说的那样结束混乱。

另外,如果多个域对象有一个setName setter,你会怎么做? 即使您使用助手类作为@dave,代码仍会被复制:调用助手实例。

现在,想一想:如果您在setName方法中能够接收到的所有参数都有效,该怎么办?当然不需要验证。 我听起来过于乐观,但可以做到。

记住你正在处理的名称,所以为什么不建模名称的概念? 这里的香草,虚拟实现,以显示想法:

public class Name 

    public static Name From(String value) { 
    if (string.IsNullOrEmpty(value)) throw new ... 
    if (value.contains(' ')) throw new ... 

    return new Name(value); 
    } 

    private Name(string value) { 
    this.value = value; 
    } 

    // other Name stuff goes here... 
} 

因为验证在制定的过程中发生的事情,你只能得到有效的名称实例。无法从“无效”字符串创建名称实例。 不仅验证代码已经集中,而且在对它们有意义的上下文中引发异常(创建Name实例)。

您可以阅读Hernan Wilkinson的“巴塔哥尼亚背后的设计原理”中的伟大设计原则(该名称示例源自它)。请务必检查ESUG 2010 Videopresentation slides

最后,我想你可能会发现Jim Shore的文章"Fail Fast"有趣。