Создайте расширенное enum с атрибутами времени выполнения - PullRequest
4 голосов
/ 28 января 2011

Я хочу упростить выбор конкретного предопределенного объекта.

В настоящее время у меня есть перечисление, определенное как

ArtworkType { Poster, Banner, Other }

И я хочу добавить атрибуты к этим ArtworkTypes, чтобы я могиспользовать их в коде в другом месте.Атрибуты ArtworkTypes являются либо предопределенными статическими метками, либо заполняются из внешнего файла конфигурации, который заполняется в классе Properties ().

В идеале я хочу сделать что-то простое, например

ArtworkType.Poster.getWidth();

Если мне нужно использовать последний класс, я думаю, что будет сложнее использовать что-то вроде

ArtworkType.getWidth(TypeEnum.Poster);

РЕДАКТИРОВАТЬ: Спасибо за ответы ниже, я заключаю, что, хотя я могу сделать это с помощью Enum, вероятно, лучше использовать внешний класс (например, ArtworkUtil) для получения атрибутов I 'м после.

Это пример кода перечисления, который я создал до сих пор (проверка ошибок не включена):

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

Хотя я понимаю, что это противоречит принципам строгого перечисления, так какзначения, связанные с Enum, являются статическими (на время приложения), это может быть меньшее из двух зол.

Единственный другой подход, который я могу придумать, - это создать класс ArtworkUtil, которыйсоздает коллекцию и заполняет все необходимые атрибуты в объект и сохраняет их в коллекции.

Доступ к этому классу в коде сделает его намного более нечитаемым (если я что-то упустил?)

Ответы [ 3 ]

13 голосов
/ 28 января 2011

Перечисления являются константами времени компиляции.Вы не можете инициализировать их из файлов свойств.

Однако они могут иметь конструкторы, методы и поля.Они также могут иметь базовые реализации методов в основном теле, которые перезаписываются в отдельных записях перечисления.

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

}

Тестовый код:

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

Вывод:

Форма: ПЛОЩАДЬ, площадь: 100,00
Форма: прямоугольник, площадь: 150,00
Форма: КРУГ, площадь: 78,54
Форма: овал, площадь: 117,81


Работа с ограничениями времени компиляции

Перечисления являются константами времени компиляции, поэтому вы не можете инициализировать их, используя непостоянные значения, что означает, что вы не можете сделать это:

SQUARE(SomeClass.getSquareValue())

Таким образом, у вас есть три основных варианта:

  1. Автоматическое создание перечисления из файла свойств

    Используйте инструмент сборки, такой как Maven, и попросите некоторый код для создания файла перечисления, преобразовав этот формат:

    ENUMNAME=property.value
    

    в эту запись enum:

    ENUMNAME("property.value")
    

    Добавьте сгенерированный enum .java к исходным текстам компиляции.С точки зрения Java, это самый чистый подход, поскольку у вас есть абсолютная безопасность во время компиляции.Проблема в том, что вам нужно перекомпилировать каждый раз, когда изменяется файл свойств.

  2. Ленивая инициализация enum (argh)

    Инициализация элементов enum с ключами свойстви когда метод enum вызывается впервые, ищите свойство из пути к классам, кэшируя его для дальнейшего использования.Это ужасный хак, но иногда он полезен.

  3. Передайте все значения в перечисления извне, используя их в качестве стратегии:

    Пример: это перечисление выглядитup Системные свойства с другим префиксом для каждой записи перечисления.

    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)
             );
         }
     }
    
2 голосов
/ 28 января 2011
public enum ArtworkType {
    Poster, Banner, Other;

    private static ResourceBundle properties;

    private static ResourceBundle getProperties() {
        if( properties == null ) {
            properties = ResourceBundle.getBundle( "artworks");
        }
        return properties;
    }

    public int getWidth() {
        return Integer.parseInt( getProperties().getString( "width."+this.name() ) );
    }
  }

Это грубое представление о том, что вам нужно сделать.Конечно, это на самом деле не код качества производства, некоторые меры безопасности были опущены для удобства чтения.

И ваш файл свойств будет выглядеть примерно так:

artworks.properties:

width.Poster=500
width.Banner=1900
width.Other=-1
0 голосов
/ 28 января 2011

Если вам нужен метод getWidth (), вы можете добавить его в перечисление, как и любой другой тип класса. Возможно, вы могли бы прояснить вашу проблему.

Из документации на enum

public enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7),
    PLUTO   (1.27e+22,  1.137e6);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    public double mass()   { return mass; }
    public double radius() { return radius; }

    // universal gravitational constant  (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    public double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    public double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...