使用子类来替换未实现接口的Java类

时间:2022-09-02 12:32:20

For example, java.io.File is just a concrete class. My replacement for it supports resolving Windows shortcuts. I need to preprocess constructor parameters to resolve possible .lnk files because the FileSystem object that does normalizing/canonicalision/resolving on the abstract paths is not accessible. The need for preprocessing rules out pure subclassing - can't do preprocessing before calling super(...) and File is immutable. So I extend File and use a delegate, overriding all of File's constructors and methods (calling super("") in all constructors).

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

This works nicely, but is obviously not ideal - if File changes, I will not have overridden any new methods or constructors and this will expose the underlying empty abstract pathname. Am I missing something obvious? It seems like there should be a simpler/better way.

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

4 个解决方案

#1


9  

In the specific case you suggest it looks to me like you're better off with a separate factory class that makes the decisions about normalizing/canonicalision/resolving.

在特定的情况下,你建议我认为你最好选择一个单独的工厂类来做出关于规范化/规范化/解决的决定。

Then you can just let File be File. Simpler.

然后你可以让文件成为文件。简单。

#2


4  

If you really want the subclass route, you can cheat the requirement that a call to super() has to be the first line of a subclass constructor by placing your cleanup code outside of your class, or in a static block:

如果你真的想要子类路由,你可以通过将清理代码放在类之外或静态块中来欺骗对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) {...}

}

The factory pattern suggested by krosenvold is another good solution.

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

#3


2  

This works nicely, but is obviously not ideal - if File changes, I will not have overridden any new methods or constructors and this will expose the underlying empty abstract pathname. Am I missing something obvious?

这很好用,但显然不理想 - 如果File更改,我将不会覆盖任何新方法或构造函数,这将公开底层的空抽象路径名。我错过了一些明显的东西吗

No, you have spotted a problem with using inheritance - that subclasses get tightly coupled to superclasses and their internals, so it can be fragile. That is why Effective Java and others say you should favour delegation before inheritance if possible.

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

I think krosenvold's solution sounds clean.

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

#4


2  

It seems to me that krosenvold's solution is the way to go.

在我看来,krosenvold的解决方案是要走的路。

But, if you need to keep record of the original path that created the file you can implement a wrapper class.

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

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;
    }
}

#1


9  

In the specific case you suggest it looks to me like you're better off with a separate factory class that makes the decisions about normalizing/canonicalision/resolving.

在特定的情况下,你建议我认为你最好选择一个单独的工厂类来做出关于规范化/规范化/解决的决定。

Then you can just let File be File. Simpler.

然后你可以让文件成为文件。简单。

#2


4  

If you really want the subclass route, you can cheat the requirement that a call to super() has to be the first line of a subclass constructor by placing your cleanup code outside of your class, or in a static block:

如果你真的想要子类路由,你可以通过将清理代码放在类之外或静态块中来欺骗对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) {...}

}

The factory pattern suggested by krosenvold is another good solution.

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

#3


2  

This works nicely, but is obviously not ideal - if File changes, I will not have overridden any new methods or constructors and this will expose the underlying empty abstract pathname. Am I missing something obvious?

这很好用,但显然不理想 - 如果File更改,我将不会覆盖任何新方法或构造函数,这将公开底层的空抽象路径名。我错过了一些明显的东西吗

No, you have spotted a problem with using inheritance - that subclasses get tightly coupled to superclasses and their internals, so it can be fragile. That is why Effective Java and others say you should favour delegation before inheritance if possible.

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

I think krosenvold's solution sounds clean.

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

#4


2  

It seems to me that krosenvold's solution is the way to go.

在我看来,krosenvold的解决方案是要走的路。

But, if you need to keep record of the original path that created the file you can implement a wrapper class.

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

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;
    }
}