Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 调用方应该在调用构造函数之前检查参数的有效性吗?_Java_Oop_Coding Style - Fatal编程技术网

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

Java 调用方应该在调用构造函数之前检查参数的有效性吗?,java,oop,coding-style,Java,Oop,Coding Style,我最近读了很多关于TDD和clean代码的书,所以我开始做一个简单的项目来使用它们,我遇到了一些我真的不确定最好的方法是什么 我有一个类,它将一个Java文件对象作为参数,期望这个文件对象必须是一个目录,并且必须以某个前缀开头。我的第一个步骤是在调用构造函数之前检查文件对象,即检查它是否是目录,并检查名称是否有效。但是我不喜欢调用方指定什么使它有效,特别是有效前缀是什么,我认为这个逻辑应该放在类本身中 我可以在构造函数中执行此检查,如果异常无效,则抛出异常,但鉴于问题的性质,如果我在一个文件的列

我最近读了很多关于TDD和clean代码的书,所以我开始做一个简单的项目来使用它们,我遇到了一些我真的不确定最好的方法是什么

我有一个类,它将一个Java
文件
对象作为参数,期望这个
文件
对象必须是一个目录,并且必须以某个前缀开头。我的第一个步骤是在调用构造函数之前检查
文件
对象,即检查它是否是目录,并检查名称是否有效。但是我不喜欢调用方指定什么使它有效,特别是有效前缀是什么,我认为这个逻辑应该放在类本身中

我可以在构造函数中执行此检查,如果异常无效,则抛出异常,但鉴于问题的性质,如果我在一个
文件的列表中迭代,则完全可以预期其中一些将不“有效”(即,它们将是文件而不是目录)那么抛出一个
异常
真的有必要吗

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");
    }
    ....
}
我考虑添加一个工厂方法来创建对象,如果
文件
无效,则返回null

public static MyObject createMyObject(File directory) {
    if (!directory.isDirectory() || !directory.getName().startsWith("Prefix")) {
        return null;
    }
    return new MyObject(directory);
}
或者,我考虑向类添加一个静态方法,在调用构造函数之前为调用方验证文件

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

if (MyObject.isValid(directory)) {
    MyObject object = new MyObject(directory);
}
那么,在干净的代码和所有OOP原则(如单一责任、耦合等)方面,哪种方法是首选的呢

更新:

在阅读了一些已经发布的答案后,我开始思考另一种可能性,这种可能性只适用于我目前的情况,而不是像我的问题真正涉及的那样一般地适用

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

public static FileFilter getFilter() {
    return new FileFilter() {
        public boolean accept(File path) {
            return path.isDirectory() && path.getName().startsWith("Prefix");
        }
    };
}
如果我的构造函数抛出了一个异常,那么这将是一个真正的异常情况,因为我们期望它只被传递给有效的目录。这样做意味着我可以从构造函数/工厂中删除检查异常的需要,因为任何异常都会指示某个地方的错误,而不是预期的行为。但它仍然留下了一个问题:是将它放在构造函数中还是放在工厂方法中

public static MyObject createMyObject(File directory) throws IllegalArgumentException{
    if (!directory.isDirectory() || !directory.getName().startsWith("Prefix")) {
        return throw new IllegalArgumentException("invalid parameters")";
    }
    return new MyObject(directory);
}
这是一个选项,它是您建议的两个选项的组合。使用工厂方法,并验证工厂方法擅长的前提条件。所以在我看来,这是一个不错的选择

为什么不按原样选择2: 因为当您可以抛出异常以警告用户某些先决条件未满足时,返回
null
是一个坏选项

更新: 此策略保证只创建处于有效状态的对象。
另外,如果您想模拟
MyObject
的实例,您可以让它实现一些使用运行时多态性的接口,并传递模拟对象。希望这是有意义的。

我认为验证代码的归属完全取决于“MyObject”类所代表的内容

如果MyObject执行一些操作,如果它有一个文件而不是一个目录,那么它应该在其构造函数中包含验证代码——这使得类是自包含的,并且允许以后可能重新使用该类


如果MyObject只是文件/目录的容器,并且其中没有特定于目录的代码,然后将验证代码放在确实需要目录而不是文件的类中。

我倾向于提供一个构造函数的组合,该构造函数在给定的参数未满足其契约时进行验证并引发异常,并辅以
静态布尔值isValid()
验证方法

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

这取决于

从编码的角度来看,最简单、最干净的方法是分解(undcked)构造函数。如果有一个合理的预期,调用方将并且应该只传入目录,那么就这样做

如果有一个合理的预期,调用方可能会在非目录中传递,那么您有两个选择:

  • 如果调用方能够处理这种情况,则让构造函数抛出一个已检查的异常
  • 如果调用者不能处理异常,如果调用者调用一个方法,你可以让你的类“什么也不做”——如果传递给构造函数的文件不是目录,基本上忽略所有“做”的请求

  • 这是一个调用,并且有一些库,用于帮助您检查传入参数。

    对我来说,第三个更可取。较短,您可以将其用于多个文件。另外,您不需要从isValid方法返回新对象,并且仅当isValid从代码的另一部分返回true时,才创建该对象。这很好,因为它分离了功能。@AliAlamiri在干净的代码方面是我的首选,因为阅读它最有意义,也就是说,读者清楚正在发生什么。我只是不能决定我是否喜欢调用方必须知道他应该首先调用isValid这一事实。为什么不将该文件传递给构造函数并在那里检查该文件是否有效呢。这会在构造对象和h时对调用方隐藏检查