3

例如,java.io.File 只是一个具体的类。我的替代品支持解析 Windows 快捷方式。我需要预处理构造函数参数以解析可能的 .lnk 文件,因为无法访问在抽象路径上执行规范化/规范化/解析的 FileSystem 对象。预处理的需要排除了纯子类化 - 在调用 super(...) 之前不能进行预处理,并且 File 是不可变的。所以我扩展了 File 并使用了一个委托,覆盖了 File 的所有构造函数和方法(在所有构造函数中调用 super(""))。

这很好用,但显然并不理想——如果 File 发生变化,我将不会覆盖任何新方法或构造函数,这将暴露底层的空抽象路径名。我错过了一些明显的东西吗?似乎应该有一个更简单/更好的方法。

4

4 回答 4

9

在您建议的特定情况下,在我看来,您最好使用一个单独的工厂类来做出有关规范化/规范化/解析的决定。

然后你可以让 File 成为 File。更简单。

于 2008-12-10T11:23:53.240 回答
4

super()如果您真的想要子类路由,您可以通过将清理代码放在类之外或静态块中来欺骗调用必须是子类构造函数的第一行的要求:

public class MyFile extends File {

    public MyFile(String path) {

        // static blocks aren't ideal, this is just for demo purposes:
        super(cleanPath(path)); 
    }

    private static String cleanPath(String uncleanPath) {...}

}

krosenvold 建议的工厂模式是另一个很好的解决方案。

于 2008-12-10T11:28:18.770 回答
2

这很好用,但显然并不理想——如果 File 发生变化,我将不会覆盖任何新方法或构造函数,这将暴露底层的空抽象路径名。我错过了一些明显的东西吗?

不,您已经发现了使用继承的问题——子类与超类及其内部紧密耦合,因此它可能很脆弱。这就是为什么 Effective Java 和其他人说如果可能的话,你应该在继承之前支持委托。

我认为 krosenvold 的解决方案听起来很干净。

于 2008-12-10T11:32:25.187 回答
2

在我看来,krosenvold 的解决方案是可行的方法。

但是,如果您需要记录创建文件的原始路径,您可以实现一个包装类。

public class FileWrapper {

    private File file;
    private String path;

    private FileWrapper(String path) {
        this.path = path;
        file = new File(preProcess(path));
    }

    private String preProcess(String path) {
        // process
        return path;
    }

    public File getFile() {
        return file;
    }

    public String getPath() {
        return path;
    }
}
于 2008-12-10T11:36:01.170 回答