【发布时间】:2013-03-11 11:31:53
【问题描述】:
我最近阅读了很多关于 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");
}
....
}
我考虑过添加一个工厂方法来创建对象并在File 无效时返回 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");
}
};
}
如果我的构造函数抛出异常,那么这确实是一种异常情况,因为期望它只被传递有效目录。这样做意味着我可以消除对构造函数/工厂检查异常的需要,因为任何异常都表明某处存在错误,而不是预期的行为。但它仍然留下了是否将其放入构造函数或工厂方法的问题。
【问题讨论】:
-
对我来说,第三个会更好。更短,您可以将它与许多文件一起使用。此外,您不需要从 isValid 方法返回新对象,并且仅当 isValid 从代码的另一部分返回 true 时才创建对象。这很好,因为它分离了功能。
-
@AliAlamiri 就干净的代码而言,这是我的偏好,因为阅读它是最有意义的,即读者很清楚正在发生什么。我只是不能决定我是否喜欢调用者必须知道他应该先调用 isValid 的事实。
-
为什么不将文件传递给构造函数并在那里检查文件是否有效。当您构造对象并让构造函数检查正在传递的文件时,这会隐藏调用者的检查?
-
@AliAlamiri 是的,这是其中一种选择,但我只是想知道在构造函数中抛出异常的最佳实践。
标签: java oop coding-style