调用者应该在调用构造函数之前检查参数的有效性吗?

Dav*_*ton 6 java oop coding-style

我最近已经阅读了很多关于TDD和清洁代码的内容,所以我开始研究一个简单的项目,使用这些,我遇到了一些我真的不确定最好的方法是什么.

我有一个类将Java File对象作为参数,期望该File对象必须是一个目录,并且必须以某个前缀开头.我的第一次传递涉及File在调用构造函数之前对对象进行检查,即检查它是否是目录并检查名称是否有效.但是我不喜欢调用者正在指定什么使它有效,特别是有效前缀是什么,我认为这个逻辑应该放在类本身.

我可以在构造函数中执行此检查,如果它无效则抛出异常,但考虑到问题的性质,如果我在Files 列表上进行迭代,那么完全可以预期其中一些不会是'有效的'(即他们将是文件而不是目录)所以投入Exception真正的保证?

public MyObject(File directory) {
    if (!directory.isDirectory()) {
        throw new IllegalArgumentException("Must be a directory");
    }
    if (!directory.getName().startsWith("Prefix")) {
        throw new IllegalArgumentException("Must start with Prefix");
    }
    ....
}
Run Code Online (Sandbox Code Playgroud)

我想过可能会添加一个Factory方法来创建对象,如果File无效则返回null .

public static MyObject createMyObject(File directory) {
    if (!directory.isDirectory() || !directory.getName().startsWith("Prefix")) {
        return null;
    }
    return new MyObject(directory);
}
Run Code Online (Sandbox Code Playgroud)

或者,我考虑在调用构造函数之前向类调用File来为类添加静态方法.

public static boolean isValid(File directory) {
    return directory.isDirectory() && directory.getName().startsWith("Prefix");
}

if (MyObject.isValid(directory)) {
    MyObject object = new MyObject(directory);
}
Run Code Online (Sandbox Code Playgroud)

那么在清洁代码和所有OOP原则(例如单一责任,耦合等)方面,这将是首选的方式吗?

更新:

在阅读了已经发布的一些答案后,我开始考虑另一种可能性,这种可能性仅适用于我目前的情况,而不是一般,因为我的问题确实存在.

作为我的调用代码的一部分,我有一个来自文件系统的路径,我列出了该目录中的所有文件,然后我将传递给MyObject构造函数的每个文件是否有效.我可以传递FileFilterlistFiles确保listFiles只返回有效目录的方法.在FileFilter可能范围内的MyObject声明:

public static FileFilter getFilter() {
    return new FileFilter() {
        public boolean accept(File path) {
            return path.isDirectory() && path.getName().startsWith("Prefix");
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

如果我的构造函数抛出异常,那么它实际上是一种异常情况,因为期望它只是传递有效的目录.这样做意味着我可以从构造函数/工厂中删除对已检查异常的需要,因为任何异常都会在某处显示错误而不是预期的行为.但它仍然存在是否将其置于构造函数或工厂方法中的问题.

rsp*_*rsp 1

我更倾向于提供一个构造函数的组合,当给定的参数没有履行由验证方法补充的契约时,该构造函数会验证并抛出异常static boolean isValid()

在循环中使用验证方法提供了一种很好的、​​可读的方式来构造有效对象,而构造函数则确保通过在需要时抛出异常来处理未验证的使用。