使用运行时属性创建扩展的"枚举"

Ome*_*ron 4 java enums class

我想简化特定预定义对象的选择.

我目前有一个枚举定义为

ArtworkType { Poster, Banner, Other }
Run Code Online (Sandbox Code Playgroud)

我想为这些ArtworkTypes添加属性,以便我可以在其他地方的代码中使用它们.ArtworkTypes的属性是预定义的静态标签,或者是从填充到Properties()类中的外部配置文件填充的.

理想情况下,我想做一些简单的事情

ArtworkType.Poster.getWidth();
Run Code Online (Sandbox Code Playgroud)

如果我必须使用最后一堂课,我认为使用类似的东西会更复杂

ArtworkType.getWidth(TypeEnum.Poster);
Run Code Online (Sandbox Code Playgroud)


编辑:感谢下面的答案,我得出结论,虽然我可以使用枚举,但最好使用外部类(例如ArtworkUtil)来检索我所追求的属性.

这是我到目前为止创建的示例枚举代码(省略错误检查):

public enum ArtworkType {
    Poster("poster"), Banner("banner"), Other("other");

    private String type;
    private Dimension dimension;

    private ArtworkType(String type) {
        this.type = type;
        this.dimension = new Dimension(Properties.getProperty("width."+type), Properties.getProperty("height."+type);
    }

    public Dimension getDimension() {
        return dimension;
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我理解这违反了严格的Enums原则,因为与Enum相关的值是静态的(在应用程序的持续时间内)它可能是两个邪恶中的较小者.

我能想到的唯一另一种方法是创建一个"ArtworkUtil"类,它创建一个集合并将所有必需的属性填充到一个对象中并将其存储在集合中.

在代码中访问该类将使其更难以理解(除非我遗漏了什么?)

Sea*_*oyd 13

枚举是编译时常量.您无法从属性文件初始化它们.

然而,它们可以具有构造函数,方法和领域.它们还可以在主体中具有在单个枚举条目中覆盖的基本方法实现.

public enum Shape{
    SQUARE(10),
    RECTANGLE(10, 15),
    CIRCLE(10){
        @Override
        public double getArea(){
            return Math.PI * Math.pow(((double) getWidth()) / 2, 2);
        }
    },
    OVAL(10, 15){
        @Override
        public double getArea(){
            return Math.PI * (getWidth()) / 2 * (getHeight()) / 2;
        }
    };

    private Shape(final int dim){ this(dim, dim); }
    private Shape(final int width, final int height){
        this.width = width; this.height = height;
    }

    private final int width;
    private final int height;

    public double getArea(){ return width * height; }

    public final int getWidth(){ return width; }

    public final int getHeight(){ return height; }

}
Run Code Online (Sandbox Code Playgroud)

测试代码:

public static void main(final String[] args){
    for(final Shape shape : Shape.values()){
        System.out.printf("Shape: %s, area: %1.2f\n", shape,
            shape.getArea());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

形状:方形,面积:100.00
形状:RECTANGLE,面积:150.00
形状:CIRCLE,面积:78.54
形状:OVAL,面积:117.81


处理编译时限制

枚举是编译时常量,因此您无法使用非常量值初始化它们,这意味着您无法执行此操作:

SQUARE(SomeClass.getSquareValue())
Run Code Online (Sandbox Code Playgroud)

所以你基本上有三个选择:

  1. 从属性文件中自动生成枚举

    使用像Maven这样的构建工具,并让一些代码为您生成枚举文件,转换此格式:

    ENUMNAME=property.value
    
    Run Code Online (Sandbox Code Playgroud)

    进入这个枚举条目:

    ENUMNAME("property.value")
    
    Run Code Online (Sandbox Code Playgroud)

    将生成的枚举.java添加到编译源.从Java的角度来看,这是最干净的方法,因为您具有绝对的编译时安全性.问题是:每次属性文件更改时都需要重新编译.

  2. 懒惰初始化枚举(argh)

    使用属性键初始化枚举项,并在首次调用枚举方法时,从类路径中查找属性,将其缓存以供进一步使用.这是一个糟糕的黑客,但它有时是有用的.

  3. 将所有值从外部传递到枚举中,将它们用作策略:

    示例:此枚举查找系统属性,每个枚举条目使用不同的前缀.

    public enum Lookup{
         ADDRESS("$1".address),
         NAME("$1".name);
         private final String pattern;
         private Lookup lookup(String pattern){
             this.pattern=pattern;
         }
         public final String lookupProperty(String input){
             return System.getProperties().get(
                 this.pattern.replace("$1",input)
             );
         }
     }
    
    Run Code Online (Sandbox Code Playgroud)