在Drools中即时更新现有枚举常量的值

huangapple go评论72阅读模式
英文:

Updating value for an existing enum constant on the go in Drools

问题

以下是翻译好的部分:

我有以下的枚举结构,我需要更改第二个参数 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 规则引擎,在其中我有枚举常量。声明不太像 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
英文:

I am having the below enum structure for which I have to change the value of the 2nd argument THREAT. The application is almost developed and is much dependant on enum types and the type can't be changed(due to a large number of the enum variables). When the application is restarted, I need the default values there. Is there any way I could change the value of THREAT on the fly?

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

Update 1
depending on the comments, I think I should update the problem a bit more. I am basically working on the drools rule engine where I am having enum constants. The declaration is not really like Java there. So, I am unable to get how do I do that. Here is the drools specific pattern.

declare enum AttackCategory
APP_DOS("as", ""),
APP_DOS1("as", ""),
APP_DOS2("as", ""),
APP_DOS3("as", ""),
APP_DOS4("as", "");
value : String
threat: String

end

答案1

得分: 0

如众多问题评论所述,您试图以不适合枚举设计或用途的方式使用枚举。与大多数出现此类情况的情况一样,您可能可以强制使其工作,但会遇到其他问题。正确的答案是重新考虑您的方案,避免试图将枚举强制为类行为。


(错误的)枚举方式

要更改枚举中的值,请在声明中添加设置器。在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约定生成getter和setter。正如您指出的,这些约定不会在枚举上生成此类方法(这应该是您试图错误使用它们的一个暗示)。

因此,如果必须使用枚举,您必须在Java中声明它们。


另一种方法:类

您的用例似乎只是变化多端的常量,那么为什么不将其作为另一种方法呢?声明一个类,包含三个字符串变量(name、thread、id)。然后,在规则中将它们全部插入工作内存,并应用默认值。在需要使用它们时,可以根据需要在内存中更新它们。

declare TraceLevel
  id: String
  name: String
  threat: String
end

rule "Prepare default trace levels"
when
  not( TraceLevel() )
then
  insert( new TraceLevel("APP_DOS", "as", "") ) // 等同于 TraceLevel.APP_DOS
  insert( new TraceLevel("APP_DOS2", "as", "") )
  // 等等
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

第一条规则 "Prepare default trace levels" 将默认级别插入工作内存。此时,工作内存中包含了一组与您的枚举值在功能上相同的对象。由于它们位于工作内存中,因此它们现在可以在随后评估的规则中使用。

请注意,此规则的条件非常简单,验证工作内存中是否存在先前的 TraceLevel 实例 - 这可以防止在某种情况下触发完全重新评估时多次执行规则。

第二个示例规则展示了如何使用 modify 规则动作 更新 "threat" 值。

在所有情况下,我都添加了一个 "id" 字段,以便您可以识别特定的 TraceLevel 实例。这些等同于 TraceLevel 枚举名称(例如 TraceLevel.APP_DOS -> id = "APP_DOS")。第二个示例展示了如何利用此 ID 获取特定的 TraceLevel 实例。

英文:

As the very many question comments say, you're trying to use an enum in a way that it's not designed or intended for. As with most cases where this happens, you can probably force it to work, but you're going to have additional problems. The correct answer is to go back to the drawing board, as they say, and come up with a solution that isn't trying to force an enum to have class behavior.


The (wrong) Enum way

To change a value on an enum, add setters to your declaration. In Java, this is done like so:

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

(Also minor comment -- the variables for 'name' and 'threat' shouldn't be fully capitalized. They should follow the naming conventions for regular variables.)

If, on the other hand, you're using Drools type declarations, you do not create methods on these structures and instead Drools generates getters and setters following bean conventions. As you point out, these conventions do not generate such methods on enums (which kind of should have been a hint that you're trying to use them the wrong way.)

So if you must use enums, you must declare them in Java.


Alternate approach: classes

Your use case appears to just be glorified constants, so why not use that as an alternative approach? Declare a class with three String variables (name, thread, id.) Then, in a rule insert them all into working memory with default values applied. When you do need to use them, you can update them in memory as needed.

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

The first rule, "Prepare default trace levels", inserts the defaulted levels into working memory. At this point, working memory contains a set of these objects which are functionally identical to your enum values. Since they're in working memory, they're now available to any subsequently evaluated rules.

Note that the condition of this rule is very simple, and verifies that there are no pre-existing TraceLevel instances in working memory -- this keeps the rule from executing multiple times if for some reason you trigger a full re-evaluation.

The second example rule shows how you'd go about updating the "threat" value using the modify rule action.

In all cases, I've added an "id" field so that you can identify specific TraceLevel instances. These are the equivalents of the TraceLevel enum names (eg. TraceLevel.APP_DOS -> id = "APP_DOS"). The second example shows how you'd leverage this ID to get a specific TraceLevel instance.

huangapple
  • 本文由 发表于 2020年10月20日 20:29:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/64445199.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定