#java #enums #drools
#java #перечисления #drools
Вопрос:
У меня есть приведенная ниже структура перечисления, для которой я должен изменить значение 2-го аргумента THREAT . Приложение почти разработано и сильно зависит от типов перечислений, и тип не может быть изменен (из-за большого количества переменных перечисления). При перезапуске приложения мне нужны значения по умолчанию. Могу ли я каким-либо образом изменить значение THREAT на лету?
enum TraceLevel {
APP_DOS("as", ""),
APP_DOS1("as", ""),
APP_DOS2("as", ""),
APP_DOS3("as", ""),
APP_DOS4("as", "");
String NAME;
String THREAT;
private TraceLevel(String name, String threat) {
this.NAME = name;
this.THREAT = threat;
}
}
Обновление 1
в зависимости от комментариев, я думаю, мне следует немного обновить проблему. Я в основном работаю над механизмом правил drools, где у меня есть константы enum. Объявление там на самом деле не похоже на Java. Итак, я не могу понять, как мне это сделать. Вот конкретный шаблон drools.
declare enum AttackCategory
APP_DOS("as", ""),
APP_DOS1("as", ""),
APP_DOS2("as", ""),
APP_DOS3("as", ""),
APP_DOS4("as", "");
value : String
threat: String
end
Комментарии:
1. Да, есть способ: использовать сеттер. Вы что-нибудь пробовали?
2. Очень плохая идея иметь изменяемые поля в перечислении, но ничто в языке Java не мешает вам это делать. Вы можете просто добавить параметр и изменить поле.
3. Это звучит как XY-проблема. Чего вы на самом деле пытаетесь достичь здесь? изменение состояния перечислений почти всегда является очень, очень плохой идеей.
4. Я только что обновил вопрос. Не могли бы вы взглянуть сейчас? @f1sh
5. Вы только что узнали, что хотите изменить внутренние компоненты константы перечисления, что противоречит концепции «константы». Это требует либо тщательного рефакторинга (даже если «приложение почти разработано»), либо больших проблем в долгосрочной перспективе.
Ответ №1:
Как говорится в очень многих комментариях к вопросам, вы пытаетесь использовать enum таким образом, для которого он не предназначен или не предназначен. Как и в большинстве случаев, когда это происходит, вы, вероятно, можете заставить его работать, но у вас возникнут дополнительные проблемы. Правильный ответ — вернуться к чертежной доске, как говорится, и придумать решение, которое не пытается заставить enum иметь поведение класса.
(Неправильный) способ перечисления
Чтобы изменить значение в перечислении, добавьте сеттеры в свое объявление. В Java это делается следующим образом:
enum TraceLevel {
APP_DOS("as", ""), ...;
String NAME;
String THREAT;
private TraceLevel(String name, String threat) {
this.NAME = name;
this.THREAT = threat;
}
public String getThreat() { return this.NAME; }
public void setThreat(String name) { this.NAME = name; }
}
(Также незначительный комментарий — переменные для ‘name’ и ‘threat’ не должны быть полностью прописными. Они должны следовать соглашениям об именовании для обычных переменных.)
Если, с другой стороны, вы используете объявления типов Drools, вы не создаете методы в этих структурах, а вместо этого Drools генерирует геттеры и сеттеры, следуя соглашениям bean. Как вы указываете, эти соглашения не генерируют такие методы в перечислениях (что должно было быть намеком на то, что вы пытаетесь использовать их неправильно.)
Поэтому, если вы должны использовать перечисления, вы должны объявить их в Java.
Альтернативный подход: классы
Ваш вариант использования, похоже, просто прославленные константы, так почему бы не использовать это в качестве альтернативного подхода? Объявите класс с тремя строковыми переменными (имя, поток, идентификатор.) Затем в правиле вставьте их все в рабочую память с примененными значениями по умолчанию. Когда вам нужно их использовать, вы можете обновлять их в памяти по мере необходимости.
declare TraceLevel
id: String
name: String
threat: String
end
rule "Prepare default trace levels"
when
not( TraceLevel() )
then
insert( new TraceLevel("APP_DOS", "as", "") ) // equivalent to TraceLevel.APP_DOS
insert( new TraceLevel("APP_DOS2", "as", "") )
// etc.
end
rule "Example rule which needs to update a Threat value"
when
$traceLevel: TraceLevel( id == "APP_DOS" )
then
modify( $traceLevel ) { threat = "new threat value" }
end
Первое правило, «Подготовить уровни трассировки по умолчанию», вставляет уровни по умолчанию в рабочую память. На данный момент рабочая память содержит набор этих объектов, которые функционально идентичны вашим значениям enum. Поскольку они находятся в рабочей памяти, теперь они доступны для любых последующих правил.
Обратите внимание, что условие этого правила очень простое и проверяет, что в рабочей памяти нет ранее существовавших экземпляров уровня трассировки — это предотвращает многократное выполнение правила, если по какой-либо причине вы запускаете полную переоценку.
Во втором примере правила показано, как вы будете обновлять значение «угроза» с помощью modify
действия правила.
Во всех случаях я добавил поле «id», чтобы вы могли идентифицировать конкретные экземпляры уровня трассировки. Это эквиваленты имен перечислений на уровне трассировки (например. Уровень трассировки.APP_DOS -> id = «APP_DOS»). Второй пример показывает, как вы могли бы использовать этот идентификатор для получения конкретного экземпляра уровня трассировки.