перечисляет как мини-таблицы данных - PullRequest
4 голосов
/ 03 декабря 2009

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

Типичным примером является enum, который я буду использовать для управления TableFormat (из застекленных списков) в JXTable (из swingx). Но вы можете сделать то же самое с TableModel и JTable. Здесь есть значение перечисления для каждого столбца в таблице.

public enum Column {
  INDEX("Order",false, Integer.class, 30) ,
  ENVIRONMENTS("Environments", false, String.class, 50) ,
  LOGICALS("Logicals", false, String.class, 100),
  URL("Url", false, String.class, 200),
  SQL("Text", false, String.class, 200),
  SOURCE("Source", false, String.class, 50) ,
  TYPE("Type", false, String.class, 40) ,
  FORMATED("Formated", false, Boolean.class, 30) ,
  ACTIVE("Active", true, Boolean.class, 30);

  private String headerName;
  private boolean isEditable;
  private Class<? extends Object> viewClass;
  private int defaultWidth;

  PlanTableColumn (String headerName, boolean isEditable, Class<? extends Object> viewClass, int defaultWidth) {
    this.headerName = headerName;
    this.isEditable = isEditable;
    this.viewClass = viewClass;
    this.defaultWidth = defaultWidth;
  }

  public String getHeaderName() {
    return headerName;
  }
  public boolean isEditable() {
    return isEditable;
  }
  public Class<? extends Object> getViewClass() {
    return viewClass;
  }
  public int getDefaultWidth() {
    return defaultWidth;
  }
  public static Column fromOrdinal(int position){
    return Column.values()[position];
  }
}

С этим определенным перечислением запись TableModel или TableFormat является рудиментарной и в некоторых случаях может использоваться повторно между несвязанными таблицами. Особенно, если каждое значение перечисления обеспечивает свою собственную реализацию getColumnValue(rowData).

Это небольшой пример, поскольку другие таблицы используют перечисления Column, которые также содержат свойства для таких вещей, как; isVisibleByDefault, sortable, maxWidth, draggable, selectable. И я буду использовать эти перечисления для гораздо большего, просто для спецификации столбцов таблицы.

Вот более крупный пример из некоторого кода, который обрабатывает объекты в базе данных Oracle.

public enum ObjectType {
    //          Display     Oracle          Gets    | Permissions     |
    // Enum     Name        Name            Synonym Execute Select DML  Compiled
    TABLE(      "Table",    "TABLE",        true,   false, true,  true,  false),
    VIEW(       "View",     "VIEW",         true,   false, true,  false, true),
    MATERIALIZED_VIEW("Materialized View", "MATERIALIZED VIEW",
                                        true,   false, true,  false, true),
    PROCEDURE(  "Procedure","PROCEDURE",    true,   true,  false, false, true),
    PACKAGE(    "Package",  "PACKAGE",      false,  false, false, false, true),
    FUNCTION(   "Function", "FUNCTION",     true,   true,  false, false, true),
    TRIGGER(    "Trigger",  "TRIGGER",      false,  false, false, false, true),
    SYNONYM(    "Synonym",  "SYNONYM",      true,   false, true,  true,  false),
    INDEX(      "Index",    "INDEX",        false,  false, false, false, false),
    CONSTRAINT( "Constraint","CONSTRAINT",  false,  false, false, false, false),
    SEQUENCE(   "Sequence", "SEQUENCE",     true,   false, true,  false, false),
    TABLE_PARTITION( "Table Partition", "TABLE PARTITION", false, false, false, false, false);

    private String name;
    private String nameLC;
    private boolean synonym;
    private boolean grantExecute;
    private boolean grantSelect;
    private boolean grantDML;
    private boolean compiled;
    // "oracleName" is what is used in oracle *_objects tables to identify the object type.
    private String oracleName;

    ObjectType(String name, String oracleName, boolean synonym, boolean execute, boolean select, boolean dml, boolean compiled) {
        this.name = name;
        this.oracleName = oracleName;
        this.nameLC = name.toLowerCase();
        this.synonym = synonym;
        this.grantExecute = execute;
        this.grantSelect = select;
        this.grantDML = dml;
        this.compiled = compiled;
    }

    public String getOracleName() {
        return oracleName;
    }
    public String getName() {
        return name;
    }
    public boolean getsSynonym() {
        return synonym;
    }
    public boolean isGrantExecute() {
        return grantExecute;
    }
    public boolean isGrantSelect() {
        return grantSelect;
    }
    public boolean isGrantDML() {
        return grantDML;
    }
    public boolean isCompiled() {
        return compiled;
    }

    public static ObjectType fromName(String string) throws UnknownObjectTypeException {
        String stringLC = string.toLowerCase();

        for ( ObjectType type : ObjectType.values() ) {
            if ( type.nameLC.equals(stringLC) ) {
                return type;
            }
        }

        throw new UnknownObjectTypeException("found no object type with name " + string);
    }

    public static ObjectType fromOracleName(String string) throws UnknownObjectTypeException {
        for ( ObjectType type : ObjectType.values() ) {
            if ( type.getOracleName().equals(string) ) {
                return type;
            }
        }
        throw new UnknownObjectTypeException("found no object type with oracle name " + string);
    }
}

Так что вы думаете? Я перебираюсь со свойствами enum?

Ответы [ 3 ]

1 голос
/ 03 декабря 2009

Если ваш код ссылается на значения перечисления (по имени), у вас есть веские основания для их использования ... и предоставления их. То же самое применимо, если вам нужно реализовать метод Column lookup(String). В противном случае они могут быть немного тяжелыми.

Но если эти вещи не представлены в общедоступных API, вероятно, не имеет значения, какой подход вы выберете.

(Если вам интересно, я считаю, что можно не использовать метод получения и установки для частного внутреннего класса, особенно если поля объявлены как окончательные. Вы можете применить это здесь ... enum объявляется как private inner ... чтобы исключить некоторые слова.)

0 голосов
/ 03 декабря 2009

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

Что-то, что я не заметил, это то, что это дает вам возможность использовать операторы switch ... Это действительно может оптимизировать ваш код, если вам нужно иметь возможность ветвиться на основе структуры (в отличие от текстовых совпадений в операторы if / else).

В конце концов, это, вероятно, дело вкуса ... если он работает и сохраняет ваш код незагроможденным без какого-либо ощутимого снижения производительности, то придерживайтесь его.

0 голосов
/ 03 декабря 2009

Я пошел еще дальше, написав перечисление, в котором CONSTANT.get_foo(mode) методы принимают другое перечисление в качестве клавиши «mode», с дважды вложенными EnumMaps (первый слой по постоянной режима, второй слой по постоянным этого перечисления), которые загружается с данными при первом обращении к заданному режиму, используя режим, чтобы решить, какой файл таблицы данных прочитать. Внутренняя часть методов получения выглядит как

synchronized(fooMap){ if(!fooMap.containsKey(mode)) loadDataFor(mode); }<br> return fooMap.get(mode).get(this)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...