我应该验证构造函数中的参数吗?

Jor*_*ksa 17 java model-view-controller design-patterns

我正在按照MVC模式创建一个Web应用程序.

在有效的Java中,作者提到在创建新对象时验证类的构造函数中的参数.

但是我没有创建一些将由第三方使用的API.我的类只接受表单输入字段中的参数,这些参数在提交给服务器之前已经过验证.

所以在这种情况下,我应该按照作者在Effective java中提到的方式创建我的类,否则它是无用的?

小智 10

它并不像读书和实现它所说的那样清晰.您需要根据具体情况思考并应用知识.

这实际上取决于如何在类中初始化变量并在对象构造后立即使用它们:

一些指示:

  • 如果变量将由类中的某些方法使用,或者对象将在构造之后立即重新使用(在大多数情况下将会重复使用),则应验证所需的值不为空或为null,避免出现令人讨厌的异常.

  • 第二次验证输入参数是指您希望将正确的值设置为特定的内部变量.如果您要求将参数约束到特定值范围,则验证非常重要.

例:

假设我们在对象中有工资上限:

int salary = 0;
int salaryCap = 1000;
Run Code Online (Sandbox Code Playgroud)

在创建期间,您可以验证传入的工资金额:

public Employee(int salary) {
 if(salary >= this.salaryCap)
  this.salary = salary;
}
Run Code Online (Sandbox Code Playgroud)
  • 类关系还决定了是否要验证值.如果参数将传递给继承链,例如,我会花时间来验证它们,特别是如果它们会影响继承链中其他对象的状态.

例:

每当我必须调用超级构造函数时,我很想验证输入:

public Employee(int salary) {
 super(salary); //validate salary against known constraints
}
Run Code Online (Sandbox Code Playgroud)
  • 变量来自哪里?如果你不信任源(比如sql参数等),那么你应该验证它们并可能在执行更多代码之前清理输入.这可以防止安全攻击.

  • 我总是厌倦在构造函数中进行验证和参数检查.我更喜欢让getter和setter来验证输入.这样,如果在创建对象时发生了某些事情,至少我得到了半工作对象的保证,而不是完全不一致的对象,其状态不容易确定.当然这取决于你的上下文,如果你的约束是严格的,你可以停止创建对象并提示客户端(用户,调用对象等)获取有效的输入参数.

使用getter/setter提供给我的优点是,对象实际上是通过调用对象提供的外部接口逐步构造的,而不是在创建期间约束验证,当发生异常时,渲染对象不可用/不稳定.

所以不是这样的:

public Employee(int salary) {
 if(salary >= this.salaryCap)
  this.salary = salary;
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢这个:

public class Employee {
 public void setSalary(int salary) {
  if(salary >= this.salaryCap)
      this.salary = salary;
 }
}
Run Code Online (Sandbox Code Playgroud)

后者使我能够干净地退出调用者的有效异常,这不会影响对象的创建(我不喜欢在构造函数中抛出异常).

简而言之,你的变量有约束吗?如果是,请在将这些约束设置为内部数据属性之前验证它们.

  • 当传入的参数无效时,你甚至不应该完成构造对象.您应该抛出[IllegalArgumentException](http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/IllegalArgumentException.html),而不是创建具有损坏的类不变量的对象.如果你的调用者给你不好的参数,那么他们应该是具有正确上下文的那些来处理它们,这可能包括从用户收集新的输入并在那之后重新尝试实例化. (15认同)