Java - 我应该在setter中读取一个值吗?

时间:2016-05-31 20:39:26

标签: java

我有一个setter,我希望它检查一个电子邮件地址是否包含字符" @"和"。" ,在设置值之前。如果电子邮件地址不包含这些字符,我希望用户再次输入电子邮件地址。我应该读取setter中的新值还是不好的实践,只能在main或不同的方法中完成?

import java.util.Scanner;
public class Person {
    private String emailAddress;
    Scanner input = new Scanner( System.in);

    public void setEmail(String email)
    {
         while(email.indexOf('@')<0 || email.indexOf('.')<0)
         {
                System.out.println("The email address must contain the characters \"@\" and \".\" ");
                System.out.println("Enter email address again:
                email = input.nextLine();
         }
    }
}

3 个答案:

答案 0 :(得分:6)

不,这是不好的做法。

问题是,如果您在没有交互式控制台的情况下调用该方法,则会卡住,例如:在单元测试中。

抛出IllegalArgumentException,让调用者实现重试(或不重试)。

在你的二传手中:

void setEmail(String email) {
  if (!email.contains("@") || !email.contains(".")) {
    throw new IllegalArgumentException("Invalid email: " + email);
  }
  this.emailAddress = email;
}

在你的来电者中:

while (true) {
  try {
    setEmail(emailAddress);
    break;
  } catch (IllegalArgumentException e) {
    // Show a message, or whatever.
  }

答案 1 :(得分:3)

你在这里混淆了功能和责任。

是的,setter应该绝对验证输入,这是使用访问器方法而不是暴露变量本身的最常见原因之一。

不,设置者不应使用System.inSystem.out来请求用户的新输入。把它留到main或者你有什么。这超出了setter的范围(以及Person类职责)

这里最好的方法是使用IllegalArgumentException并让调用代码按照自己的意愿处理。

public void setEmail(String email)
{
     if(email.indexOf('@')<0 || email.indexOf('.')<0)
     {
            throw new IllegalArgumentException("Invalid email address.");
     }
     this.email = email;
}

您的客户端代码可以像这样使用它

boolean goodEmail = false;
while (!goodEmail) {
  String inputEmail = getTheEmailAddressFromTheUserSomehow();

  try {
    person.setEmail(inputEmail);
    goodEmail = true;
  } catch (IllegalArugmentException e) {
    //try again!
    //or don't, depends on the workflow of the application
  }
}

答案 2 :(得分:2)

一般来说,如果某个方法做了名称以外的任何其他操作,那么这是一个坏主意。

如果该方法被称为setFoo(),人们希望它更新名为foo的字段,而不执行任何其他操作。当然,你可以(确实你应该)验证你的输入并抛出IllegalArgumentException,如果它不是你想要的,但没有别的。

这通常被称为&#34; 最少惊喜的原则&#34;它是编写代码的一个非常有用的设计原则。

另一个一般的经验法则是,方法应尽可能只负责一件事。

当然是什么&#34;&#34;&#34;会有所不同,它可能是非常具体的(例如:&#34;此方法将两个参数相乘&#34;)或者它可能更通用(&#34;此方法处理我的所有输入&#34;),但如果你不能用一个简单的句子来解释这个方法的作用,它可能做得太多了。

(作为练习,请考虑一下你如何向朋友解释setEmail()做了什么。大声说出这些话。它确实有用。)

当你进行I / O时,这更为重要,就像你在你的例子中所做的那样:从Scanner读取的时间应该是非常清楚的,否则它几乎不可能遵循在该计划的哪个阶段预期的输入。在这种情况下,即使您的Person课程也不应对Scanner做任何事情。处理其他地方的输入并让Person类只代表一个人。