NRules: как организовать правила в модулях и включить / отключить другие правила - PullRequest
0 голосов
/ 25 октября 2018

Я начинаю с NRules.Вот краткое описание некоторых ключевых требований для приложения, которое я создаю:

  1. Некоторые из правил определяют, следует ли применять группы других правил.Например (в псевдокоде): «когда тип vehicle относится к автомобилю, примените все правила, применимые к автомобилям».

  2. Некоторые правила определяют, что определенные правила следует исключить.

  3. Может быть много типов vehicle;в идеале я не хочу загружать все правила для всех транспортных средств при запуске.

Это означает, что правила должны быть организованы в модули, которые каким-либо образом включаются / отключаются во время выполнения.Мне пришло в голову несколько решений:

  • Помечать правила и использовать фильтры Повестки дня для фильтрации правил в зависимости от службы, которая используется для включения / выключения добавления правил в повестку дня.Я попробовал это, и это не совсем работает так, как мне хотелось бы, потому что двигатель не воспринимает изменение службы.

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

  • Загрузка новых групп правил во время выполнения правил.Я не уверен, как это сделать, если это рекомендуется или должно работать.

Есть ли правильный способ сделать то, что я пытаюсь сделать?

1 Ответ

0 голосов
/ 12 ноября 2018

На самом высоком уровне есть два способа контролировать, какие правила применяются (и даже рассматриваются):

  1. Загрузить все правила в сеанс и обработать их в рамках логики правил
  2. Загрузка групп правил в разные сеансы и наличие неких мета-правил, которые отправляют элемент управления в соответствующий поднабор правил.

Одним из упомянутых вами требований было следующее:даже не загружать правила, которые вам не нужны.Если это действительно так, я думаю, что вы находитесь прямо во второй группе решений.Движок не имеет встроенных механизмов, облегчающих этот сценарий, поэтому вам придется создавать его самостоятельно.На мой взгляд, вам понадобится набор мета-правил, загруженных в их собственный сеанс, которые вычисляют критерии, которые вы потом будете использовать для загрузки определенных правил.Например, у вас будет правило, которое соответствует транспортному средству, если оно является автомобилем, и вставляет тег «автомобиль» в сеанс.Некоторые другие мета-правила могут вычислять больше тегов.Затем вы будете использовать вычисленные теги для загрузки дополнительных наборов правил, например, загрузить все правила, которые имеют любой из этих вычисленных тегов, и скомпилировать их в отдельный сеанс, а затем выполнить ваши факты в соответствии с этими загруженными правилами.Правила должны быть скомпилированы и загружены в новый сеанс, потому что после компиляции фабрика сеансов является неизменной, поэтому новые правила не могут быть добавлены к ней.

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

Например, у вас может быть правило, которое соответствует Транспортному средству, если это автомобиль, и выдает новый факт - Автомобиль, этот автомобиль.конкретные правила будут использовать позже:

Vehicle vehicle = null;
When()
    .Match(() => vehicle, v => v.VehicleType == VehicleType.Car);

Then()
    .Yield(_ => new Car(vehicle));

Тогда ваши правила, относящиеся к вашему автомобилю, будут выглядеть так:

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

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

...