2

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

一个博客有很多文章,一篇文章有​​很多评论

还想象一下,我有两个博客,博客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

4

1 回答 1

0

在阅读了有关访问者模式的更多信息后,我认为它的 Rubyish 变体是解决此问题的最合适的方法。

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

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

下面是我的实现,基于各种参考,我可以将它包装成一个 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"?
于 2012-11-13T15:58:46.573 回答