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

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

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

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

那么在这种情况下,我应该按照作者在 Effective java 中提到的方式创建我的类,还是没用?


答案 1

它不像读一本书并实现它所说的那样清晰。您需要思考并将知识应用于您的特定情况。

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

一些提示:

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

  • 验证输入参数的第二次是当您期望将正确的值设置为特定的内部变量时。如果需要将参数约束到特定值范围,则进行验证非常重要。

例:

假设我们在对象中有一个工资帽:

int salary = 0;
int salaryCap = 1000;

在创建过程中,您可以验证传递的工资金额:

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

例:

每当我必须调用超级构造函数时,我都会尝试验证输入:

public Employee(int salary) {
 super(salary); //validate salary against known constraints
}
  • 变量从何而来?如果您不信任源代码(如sql参数等),那么您应该在执行进一步的代码之前验证它们并可能清理输入。这可以防止安全攻击。

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

使用 getters/setters 为我提供的优点是,对象实际上是通过调用对象提供的外部接口来逐步构造的,而不是在创建过程中约束验证,当发生异常时,会使对象不可用/不稳定。

所以不是这个:

public Employee(int salary) {
 if(salary >= this.salaryCap)
  this.salary = salary;
}

我更喜欢这个:

public class Employee {
 public void setSalary(int salary) {
  if(salary >= this.salaryCap)
      this.salary = salary;
 }
}

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

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


答案 2

我建议验证域中的数据,并在字段未正确填写时返回(自定义)异常。这样,您就可以实现不同的UI,而无需再次执行整个验证过程,最好尽可能地将其分开。


推荐