Звучит как хорошая ситуация для наблюдателя.Вот пример этого в ruby:
require 'observer'
class Node
attr_accessor :id
@@current_node_id = 0
def initialize
@@current_node_id += 1
id = @@current_node_id
end
include Observable
attr_reader :value
protected
def value=(new_value)
return if @value == new_value
old_value = @value
@value = new_value
changed
notify_observers(id, old_value, @value)
end
end
class ValueNode < Node
def initialize(initial_value)
super()
@value = initial_value
end
def value=(new_value)
super(new_value)
end
end
class SumNode < Node
def initialize(*nodes)
super()
@value = nodes.map(&:value).inject(0, &:+)
nodes.each do |node|
node.add_observer(self)
end
end
def update(id, old_value, new_value)
self.value = self.value - old_value + new_value
end
end
def test
v1 = ValueNode.new 4
v2 = ValueNode.new 8
sum = SumNode.new(v1, v2)
sum2 = SumNode.new(v1, sum)
v2.value = 10
p sum.value
p sum2.value
end
test()
Обратите внимание, что значение SumNode
не пересчитывается при каждом запросе - вместо этого оно обновляется при обновлении одного из его узлов значений.Это работает рекурсивно, так что внутренний SumNodes
также запускает обновления.Поскольку уведомление включает в себя уникальный id
узла, можно писать более сложные Node
типы, например, содержащие формулы.
См. http://www.ruby -doc.org / stdlib / libdoc / наблюдатель / rdoc / index.html для получения дополнительной информации о Observable