Включение изменяемого состояния в API для обработки правил - PullRequest
2 голосов
/ 06 января 2012

У меня есть структура данных RuleTree, которая представляет собой дерево правил, которые используются для обработки входящих элементов данных.

  • RuleTree в настоящее время является неизменной структурой данных, содержащей произвольное количество (возможно, вложенных) правил.
  • Существует несколько потоков, которые будут одновременно применять одно и то же RuleTree к разным элементам входных данных
  • RuleTree применяется для ввода данных в одну или несколько фаз. Решение о том, какие фазы применить, зависит от вызывающего кода.

Типичный поток управления будет выглядеть примерно так:

ruleTree.applyStage1(data);
..
// other stuff happens
..
ruleTree.applyStage2(data);
..
// other stuff happens
..
ruleTree.applyStage3(data);

В настоящее время это работает нормально. Однако теперь у меня есть требование вычислять некоторую дополнительную информацию о состоянии во время обработки RuleTree (например, подсчет количества совпадений для определенного правила в дереве). Насколько я вижу, у меня есть несколько вариантов:

  • Сделайте RuleTree изменяемым и включите его для хранения информации о состоянии, которую можно будет прочитать позже. Однако это усложнит параллелизм, поскольку разным потокам потребуются разные копии RuleTrees.
  • Добавление локального состояния потока в RuleTrees - чтобы информация о состоянии могла быть рассчитана и сохранена в RuleTree, но разные потоки не будут попирать информацию о состоянии друг друга. Однако это означает, что все фазы должны быть гарантированно запущены в одном потоке.
  • Имеется отдельный объект для информации о состоянии , который может быть передан в качестве дополнительного параметра в ruletree, e.g. ruleTree.applyStage1(data, state). Это делает RuleTrees красивым и неизменным, но делает их более сложными для вызывающей стороны, поскольку вызывающий код теперь должен отдельно настраивать данные состояния и управлять ими.

Какой подход лучше всего подходит и почему?

1 Ответ

2 голосов
/ 06 января 2012

Используйте подход «отдельный объект для информации о состоянии», потому что он не страдает от недостатков, присущих другим подходам, которые вы рассматриваете.Более того, главный недостаток модели «отдельный объект», заключающийся в том, что от пользователя требуется передать состояние каждому методу RuleTree, может быть легко исправлен.

Рассмотрим прокси для RuleTree.Я буду использовать Ruby в качестве работоспособного приближения для псевдокода:

class RuleTreeProxy

  def initialize(ruleTree)    # Constructor
    @ruleTree = RuleTree
    @state = RuleTreeState.new
  end

  def state
    return @state
  end        

  def applyStage1(data)
    @rule_tree.applyStage1(@state, data)
  end

  def applyStage2(data)
    @rule_tree.applyStage2(@state, data)
  end

  # etc.

end

@ обозначает переменную члена объекта.

Любой, кому нужно использовать RuleTree, создает RuleTreeProxy и вызываетвместо этого:

proxy = RuleTreeProxy.new(ruleTree)
proxy.applyStage1(data)
proxy.applyStage2(data)
...

Объект состояния содержит средства доступа для извлечения полезной информации об обработке, выполненной RuleTree:

matches = proxy.state.numberOfMatches

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

...