26

我一直很好奇的东西

public class FileDataValidator {

private String[] lineData;

public FileDataValidator(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
    }
    catch(InvalidFormatException e)
    {
        e.printStackTrace();
    }

}

//validation methods below all throwing InvalidFormatException

不建议在我的构造函数中包含 try/catch 块吗?我知道我可以让构造函数将异常抛出给调用者。你们在调用我在构造函数中所做的方法时更喜欢什么?在调用类中,您更愿意创建 FileDataValidator 的实例并在该实例上调用方法吗?只是有兴趣听到一些反馈!

4

3 回答 3

23

在您显示的代码中,验证问题不会传达回创建此对象实例的代码。这可能不是一件好事。

变体1:

如果您在方法/构造函数中捕获异常,请务必将某些内容传回给调用者。如果一切正常,您可以放置​​一个isValid设置为 true 的字段。看起来像这样:

private boolean isValid = false;

public FileDataValidator(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
        isValid = true;
    }
    catch(InvalidFormatException e)
    {
        isValid = false;
    }
}

public boolean isValid() {
    return isValid;
}

变体2:

或者您可以让异常或其他一些异常传播给调用者。我已将其显示为非检查异常,但根据您的异常处理宗教做任何工作:

public FileDataValidator(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
    }
    catch(InvalidFormatException e)
    {
        throw new com.myco.myapp.errors.InvalidDataException(e.getMessage());
    }

}

变体3:

我要提到的第三种方法有这样的代码。在调用代码中,您必须调用构造函数,然后调用build()可以工作或不工作的函数。

String[] lineData = readLineData();
FileDataValidator onePerson = new FileDataValidator();
try {
    onePerson.build(lineData);
} catch (InvalidDataException e) {
    // What to do it its bad?
}

这是课程代码:

public FileDataValidator() {
    // maybe you need some code in here, maybe not
}

public void build(String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();

    try
    {
        validateName();
        validateAge();
        validateTown();
    }
    catch(InvalidFormatException e)
    {
        throw new com.myco.myapp.errors.InvalidDataException(e.getMessage());
    }

}

当然,该build()函数可以使用isValid()您调用的方法来查看它是否正确,但是对于我来说,异常似乎是构建函数的正确方法。

变体4:

我要提的第四种方法是我最喜欢的。它有这样的代码。在调用代码中,您必须调用构造函数,然后调用build()可以工作或不工作的函数。

这种方式遵循 JaxB 和 JaxRS 的工作方式,这与您所拥有的情况类似。

  1. 外部数据源 - 您有一个文件,它们有 XML 或 JSON 格式的传入消息。
  2. 构建对象的代码——你有你的代码,它们的代码库根据各种 JSR 中的规范工作。
  3. 验证与对象的构建无关。

调用代码:

String[] lineData = readLineData();
Person onePerson = new Person();
FileDataUtilities util = new FileDataUtilities();
try {
    util.build(onePerson, lineData);
    util.validate(onePerson);
} catch (InvalidDataException e) {
    // What to do it its bad?
}

这是数据所在的类代码:

public class Person {
    private Name name;
    private Age age;
    private Town town;
... lots more stuff here ...
}

以及用于构建和验证的实用程序代码:

public FileDataValidator() {
    // maybe you need some code in here, maybe not
}

public void build(Person person, String[] lineData){

    this.lineData = lineData;
    removeLeadingAndTrailingQuotes();
    setNameFromData(person);
    setAgeFromData(person);
    setTownFromData(person);
}

public boolean validate(Person person) {

    try
    {
        validateName(person);
        validateAge(person);
        validateTown(person);
        return true;
    }
    catch(InvalidFormatException e)
    {
        throw new com.myco.myapp.errors.InvalidDataException(e.getMessage());
    }

}
于 2013-05-28T15:45:09.127 回答
4

您应该考虑静态工厂模式。将您的全参数构造函数设为私有。提供静态 FileDataValidator(args...) 方法。这接受并验证所有参数。如果一切正常,它可以调用私有构造函数并返回新创建的对象。如果有任何失败,抛出一个异常通知调用者它提供了错误的值。

我还必须提到:catch (Exception e) { printSomeThing(e); }

是你可以用异常做的最致命的反模式。是的,你可以在命令行上读取一些错误值,然后呢?调用者(提供了错误值)不会收到错误值的通知,程序将继续执行。

于 2013-05-28T15:52:30.233 回答
2

我的偏好是通过知道如何处理它们的代码来处理异常。在这种情况下,我假设创建 FileDataValidator 的代码知道如果文件数据无效会发生什么,并且应该在那里处理异常(我主张传播给调用者)。

在讨论最佳实践时——类名 FileDataValidator 对我来说很臭。如果您正在创建的对象存储文件数据,那么我将其称为 FileData - 也许使用 validate 方法?如果您只想验证文件数据,那么静态方法就足够了。

于 2013-05-28T15:48:48.060 回答