Java:静态抽象(再次) - 最佳实践如何解决

时间:2011-01-18 22:59:23

标签: java static abstract

我理论上理解Java中没有 抽象静态 的原因,如Why can't static methods be abstract in Java中所述。

但我该如何解决这个问题?

我的应用程序使用几种类型的文件,我想分配静态属性,如该文件类型的描述(如“数据文件”,另一种是“配置文件”等)。 显然,我会把它放到一个静态字符串中,以便在不实例化文件的情况下访问描述(对于GUI f.i.很有用)。 另一方面,显然所有文件类型都应该有一些常见的方法,如getStatus(),显然我想从公共超类MyFileType继承。

getDescription()当然在超类中是抽象的。

尝试使用超类和接口的组合,但类似的问题:不允许静态实现抽象方法。

Java大师将如何解决这个问题? 我想创建它真的是一个糟糕的实现吗?

非常感谢, 菲利普

9 个答案:

答案 0 :(得分:30)

重述问题:您希望每个文件类型的类具有关于类型的静态可用信息(例如,名称和描述)。

我们可以轻松地在那里获得部分:为您的类型信息创建一个单独的类,并在每个文件类型类中拥有一个静态实例(适当实例化)。

package myFileAPI;

public class TypeInfo { 
    public final String name;
    public final String description;

    public TypeInfo(String name, String description) {
        this.name = name;
        this.description = description;
    }
}

并且说:

package myFileAPI;

public class TextFile {
    public static final TypeInfo typeInfo
                   = new TypeInfo("Text", "Contains text.");
}

然后你可以做类似的事情:

System.out.println(TextFile.typeInfo.name);

(当然,您也可以在TypeInfo中使用getter来封装基础字符串。)

但是,正如您所说,我们真正想要的是在编译时强制在所有每个文件类型的类中存在特定的签名静态方法但是,“明显的”设计路径导致需要在不允许的公共超类中使用抽象静态方法。

我们可以在运行时强制执行此,这可能足以确保其正确编码。我们介绍一个File超类:

package myFileAPI;

public abstract class File {

    public static TypeInfo getTypeInfo() {
        throw new IllegalStateException(
                    "Type info hasn't been set up in the subclass");
    }

}

如果TextFile现在extends File,我们将在运行时调用TextFile.getTypeInfo()时获得此异常,除非TextFile具有相同的签名方法。

这是非常微妙的:即使在TextFile中没有这样的方法,仍会编译TextFile.getTypeInfo()的代码。即使静态方法在编译时绑定,编译器仍然可以查看类层次结构以确定编译时静态调用目标

所以,我们需要像:

这样的代码
package myFileAPI;

public class TextFile extends File {

    private static final TypeInfo typeInfo
                      = new TypeInfo("Text", "Contains text.");

    // Shadow the superclass static method
    public static TypeInfo getTypeInfo() {
        return typeInfo;
    }

}

请注意,我们仍然是 shadowing 超类方法,因此File.getTypeInfo()仍然可以被“无意义地”调用。

答案 1 :(得分:7)

这听起来是抽出软件工程基本定理的好时机:

  

任何问题都可以通过添加另一层间接来解决。

你在这里遇到的问题是一个文件带有多条信息 - 文件的类型,文件的描述,文件内容等等。我建议将它分成两类 - 一个类表示磁盘上的具体文件及其内容,第二个类是某种文件类型的抽象描述。这将允许您以多态方式处理文件类型类。例如:

public interface FileType {
     String getExtension();
     String getDescription();

     /* ... etc. ... */
}

现在,您可以为您使用的每种文件类型创建子类:

public class TextFileType implements FileType {
     public String getExtension() {
         return ".txt";
     }
     public String getDescription() {
         return "A plain ol' text file.";
     }
     /* ... */
}

然后,您可以拥有这些类型对象的大型存储库,这样您就可以查询其属性,而无需打开该类型的文件。您还可以将类型与您使用的每个实际文件相关联,只需将其存储为FileType引用。

答案 2 :(得分:3)

问题不够明确,无法提供客观答案。由于我不能给你一条鱼,这个答案更多的是“教你钓鱼

当遇到像这样的设计问题时,你会认为“ duh ..现在确定为什么这么简单的事情是如此困难”,你经常会将它设计为公然错误或者你是过于复杂的事情。如果我正确地同情,设计问题似乎是一个“共同要求”,但语言不允许它。

  • 追溯您的设计步骤/决定
  • 质疑所有“明显的”和“偏离过程”你基于你的设计(你在上面使用了其中的一些)
  • 看看事情是否可以简化(不要将任何OO概念推向极端。根据投资回报率做出妥协)

......你很可能会得到一个可以接受的答案。

如果你还没有,请回复你认为你想要的类和接口(编译错误,因为语言不允许某些事情),也许我们可以帮助你调整你的设计。

答案 3 :(得分:3)

注释可能适用于您的目的。

@FileProperties(desc="data file")
public class DataFile extends XFile { ... }

FileProperties props = DataFile.class.getAnnotation(FileProperties.class);
String desc = props.desc(); 

访问信息仍需要反射,但它比使用静态字段/方法要好一些。

Java编译器不强制所有子类都这样注释。您可以将您的逻辑添加到编译器(使用注释处理),但这太复杂了。可以在运行时检查它。

更新

这也是可能的:

@FileInfoClass ( DataFileInfo.class )
@public class DataFile

答案 4 :(得分:0)

听起来你需要使用单身人士。基本上,您调用一个静态方法,如MyFileTypes.getDataFileInstance(),它创建一个对象的单个实例(或重用,如果已经创建),当您第一次创建它时,根据需要设置'常量'。我会看看我是否能找到一个很好的例子,但你的帖子并不是很清楚如何使用它。

答案 5 :(得分:0)

您可以创建一个包含所需信息的FileMetadata类。当您的应用程序启动时,您可以创建FileMetadata的实例,并保留静态指针,以便您可以从JVM中的任何位置访问它们。

这样你就可以将抽象的东西放在实际的实例中;任何不需要抽象语义的东西都可以是静态的......

答案 6 :(得分:0)

我不知道java guru如何解决它,但我可能会创建一个resource bundle,其中包含属性文件中的所有描述:

com.bigcompany.smallapp.files.DataFile=Data file
com.bigcompany.smallapp.files.ConfigFile=Config file

处理捆绑包可以方便地放在超类或其他地方。

另一种选择是使用反射来访问每个子类中的静态字段,但是你需要确保所有子类都有一个具有相同名称的静态字段。

也可能有其他选项,甚至重构代码,以便子类型不是由每个单独的类表示,但通常没有防水解决方案。

答案 7 :(得分:0)

不要将静态属性实际放在静态属性中,而是将对MyFileTypeDescription的引用作为静态属性。

class MyFileType {
   static MyFileTypeDescription description;
   ...
   <your regular attributes>
}
abstract class MyFileTypeDescription {
  String name;
  abstract String getDescription();
}

如果我正确理解你的问题,那就是这样。

答案 8 :(得分:0)

我基本上有完全相同的问题。

你可能想看一下 solutions suggested to me in my question

我喜欢Bozho的想法,但据他自己说这是一个坏主意。 :)我想更好的程序员可以解释为什么会如此。 Ralph和Jon Skeet的解决方案也有效。