Работа с перечислениями в среде с несколькими приложениями

Наша фирма разрабатывает в основном на Java и поддерживает ряд «живых» систем (в основном длительно работающие серверные процессы), все из которых зависят от общих справочных данных и перечислений. Иногда определение перечисления расширяется, чтобы включить новое значение, и в этом случае мы в настоящее время повторно развертываем все наши приложения, когда это происходит, причина в том, что каждое наше приложение имеет личную папку "lib", содержащую все библиотеки jar ( включая библиотеку "enum entity"). Очевидно, это нежелательно, и поэтому мне было бы интересно услышать рекомендации или подходы других людей.

Идеи, которые я придумал:

  1. Изменение сценария запуска каждого приложения для получения самой последней версии библиотеки "enum entity" и добавление файла jar в путь к классам.
  2. Какой-то механизм для динамической загрузки класса нового определения перечисления во время выполнения.

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

switch(enumVal) {
  case A:
    // Do something.
    break;
  case B:
    // Do something.
    break;
  default:
    throw new IllegalArgumentException("Invalid enum value: " + enumVal);
}

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


person Adamski    schedule 28.10.2011    source источник
comment
Я думаю, вам нужно переосмыслить дизайн вашего приложения. Помните: инкапсулируйте то, что меняется.   -  person Mister Smith    schedule 28.10.2011
comment
Когда определение перечисления расширяется, все ли ваши приложения сразу же начинают использовать новое значение? Для чего вы используете эти перечисления? Если вы добавляете новое значение в перечисление, но нигде не ссылаетесь на него в коде приложения, будет ли оно по-прежнему использоваться приложением (например, с помощью метода valueOf())?   -  person socha23    schedule 28.10.2011
comment
Перечисления — это константы времени компиляции. Так что перезагрузки недостаточно. Вы должны перекомпилировать все классы, которые их используют, если вы что-то меняете в перечислении.   -  person ssedano    schedule 28.10.2011
comment
@Udo Fholl: Не совсем так, поскольку Java выполняет (позднее) связывание во время выполнения и только по имени. Если в любой файл класса (видимый интерфейс) добавляются только новые элементы, существующий код не нужно перекомпилировать.   -  person JimmyB    schedule 29.10.2011


Ответы (2)


Г-н Смит прав: расширение перечислений или констант int старой школы «перечисления», если на то пошло, вряд ли можно сделать правильно и, как правило, не является хорошим подходом.
Как вы подразумеваете, новые значения перечисления требуют специального поведение/обработка клиентов, использующих их. Таким образом, после изменения перечисления вы должны изменить и клиентов. Это действительно плохо, и вы действительно должны попытаться перепроектировать его по-другому.

person JimmyB    schedule 28.10.2011
comment
Да, но даже перечисления могут иметь методы. Вы застряли с одноуровневой иерархией наследования, но они могут вести себя почти так же, как обычный класс. У вас также могут быть разные переопределения для каждого метода констант перечисления. Поэтому вместо того, чтобы кодировать этот переключатель или if-else, переместите то, что нужно сделать, внутрь каждого метода перечисления/класса и вызовите его из клиентского кода. - person Mister Smith; 28.10.2011
comment
Я снова согласен и могу добавить: Если специализированное поведение/обработка можно реализовать в одном месте, в самих перечислениях, чтобы оно было одинаковым для всех клиентов , он не должен быть реализован в клиентах в первую очередь. - person JimmyB; 28.10.2011
comment
О, и обратите внимание, что перечисления не поддерживают наследование и, следовательно, полиморфизм. - person JimmyB; 28.10.2011
comment
Константы перечисления являются своего рода подклассами класса перечисления. У вас может быть постоянное тело класса, чтобы переопределить метод, определенный в перечислении для определенной константы перечисления. Это не то, что я называю чистым дизайном, но он работает. - person Mister Smith; 31.10.2011
comment
Это правильно, но клиенты не могут создавать свои собственные реализации предоставленного типа перечисления для изменения поведения. - person JimmyB; 31.10.2011

Объектная ориентация была придумана специально для решения этой проблемы: ваш коммутатор — это просто явная виртуальная таблица, тогда как неявная виртуальная таблица была бы намного лучше. Вам следует подумать о перепроектировании вашего приложения, чтобы использовать интерфейсы/базовые классы вместо перечислений.

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

Вероятно, самый простой способ избежать перекомпиляции — использовать внедрение зависимостей. С помощью таких фреймворков, как Spring, вы можете иметь один или несколько файлов конфигурации, в которых вы указываете объекты, которые необходимо создать, а затем вы можете загружать их по имени.

person Nicola Musatti    schedule 28.10.2011
comment
Это интересно. Давайте представим, что у него был правильный объектно-ориентированный дизайн. Когда-нибудь будут введены новые требования и должен быть добавлен новый класс (как минимум). Какие есть варианты поставить его в систему без перекомпиляции? - person Mister Smith; 28.10.2011
comment
Итак, теперь вместо закодированной фабрики у нас есть XML. Но опять же, новый класс должен быть введен в систему, чтобы среда DI могла его инстанцировать, не так ли? Как без перекомпиляции? Просто добавить файл класса в какую-то папку? И еще вопрос: определяет ли DI framework, что XML был изменен, или нужен перезапуск? - person Mister Smith; 28.10.2011
comment
Да, вы можете добавить файл класса в папку или банку, хотя последнее, вероятно, предотвратит горячее добавление. Я не знаком с деталями автоматического обновления конфигурации, так как мне никогда не приходилось делать это самому. - person Nicola Musatti; 28.10.2011