用于递归更新两个相关对象图的模式

时间:2012-11-09 23:15:27

标签: ruby-on-rails ruby design-patterns object-graph

想象一下,我有一个对象模型:

博客有很多文章,文章有很多评论

想象一下,我还有两个博客,博客A 博客B

Blog A - Article id 1 - Comment id 1 "fun stuff"
       - Article id 2 - Comment id 2 "cool"

Blog B - Article id 3 - Comment id 3 "no fun"

我需要比较博客A和博客B的对象图,并根据博客A中对象的更新博客B.

在这种情况下,博客B应将注释3更改为“有趣的东西”,并实例化具有与第2条和注释2相同的值的新对象。

递归地移动图形是一个显而易见的解决方案,但逻辑变得复杂。我宁愿不重新发明轮子......有没有一种模式或过程可以做到这一点?

我正在使用Ruby / Rails

1 个答案:

答案 0 :(得分:0)

在阅读了有关访客模式的更多信息之后,我决定使用它的Rubyish变体来解决这个问题。

访问者模式允许您将用于遍历层次结构的算法与要在层次结构中的每个节点上执行的代码分开。可以使用map或inject / fold来实现更实用的方法......但是当我想重用运算符时,将它们分成单独的类似乎更容易。

层次结构在每个模型中实现,它应该定义一个返回子节点的“children”方法。

以下是我的实现,基于各种引用,我可以将其包装成gem。

module Visitable
  def accept visitor
    child_vals = []
    if respond_to?(:children)
      children.each do |child|
        child_vals << child.accept(visitor)
      end
    end
    val = visitor.visit(self)
    child_vals.any? ? val + child_vals : val
  end
end

class Survey
  attr_accessor :name, :children

  include Visitable

end

class Category
  attr_accessor :name, :children

  include Visitable

end

class Question
  attr_accessor :name
  include Visitable
end

s = Survey.new
s.name = 's1'
c = Category.new
c.name = 'c1'
c2 = Category.new
c2.name = 'c2'
q = Question.new
q.name = 'q1'
q2 = Question.new
q2.name = 'q2'

c.children = [q]
c2.children = [q2]
s.children = [c,c2]

class ReturnVisitor
  def visit obj
    obj.name
  end
end

s.accept(ReturnVistor.new)
-> ['s1', ['c1', ['q1'], ['c2', ['q2']]]]

# "poorly implemented lisp"?