代码之家  ›  专栏  ›  技术社区  ›  Captain Whippet

NRules:如何在模块中组织规则,并与其他规则一起启用/禁用

  •  0
  • Captain Whippet  · 技术社区  · 6 年前

    我开始用NRules。以下是我正在构建的应用程序的一些关键要求:

    1. 某些规则决定是否应应用其他规则组。例如(在伪代码中):“当 vehicle

    2. 某些规则将决定应排除特定规则。

    3. 可能有多种类型的

    这意味着规则应该组织成模块,在执行过程中以某种方式启用/禁用这些模块。我想到了一些解决办法:

    • 标记规则并使用议程筛选器根据用于启用/禁用规则添加到议程的服务筛选规则。我已经试过了,但它并没有像我想的那样工作,因为发动机没有接收到对服务的更改。

    • 添加确定是否应应用规则的规则,并在每个规则的匹配条件中使用该规则。这导致每个规则中都有大量重复的代码,我不太喜欢。

    • 在规则执行期间加载新的规则组。我不知道如何做到这一点,如果它是建议或应预期的工作。

    有没有正确的方法来做我想做的事?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Sergiy Nikolayev    6 年前

    在最高级别上,有两种方法可以控制应用了哪些规则(甚至考虑了哪些规则):

    您提到的一个要求是,甚至不加载您不需要的规则。如果真是这样的话,我认为你完全属于第二组解决方案。引擎没有任何内置机制来促进这种情况,因此您必须自己构建它。在我看来,您需要一组元规则,加载到它们自己的会话中,用于计算标准,然后用于加载特定规则。例如,如果一辆车是一辆车,那么您将拥有一个与之匹配的规则,并在会话中插入一个“car”标记。其他一些元规则可能会计算更多的标记。 然后您将使用计算标记加载其他规则集,例如,加载所有具有这些计算标记的规则,并将它们编译到单独的会话中,然后根据这些加载的规则运行事实。这些规则需要编译并加载到新的会话中,因为一旦编译,会话工厂是不可变的,因此不能向其中添加新的规则。

    如果您可以放宽不加载所有规则的要求,那么您还有一些选择。你已经提到了问题中的一些选项,但我认为你最好的办法是使用前向链接来实现你想要的。我个人认为这比尝试动态加载和编译规则要好。

    Vehicle vehicle = null;
    When()
        .Match(() => vehicle, v => v.VehicleType == VehicleType.Car);
    
    Then()
        .Yield(_ => new Car(vehicle));
    

    然后,您的汽车特定规则将如下所示:

    Car car = null;
    When()
        .Match(() => car)
        //...
    

    在生成car事实的规则触发之前,不会对任何特定于car的规则进行评估。

    推荐文章