2

私がオブジェクトモデルを持っていると想像してください:

ブログにはたくさんの記事があり、記事にはたくさんのコメントがあります

また、ブログAブログBの2つのブログがあるとします。

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

ビジター パターンについて詳しく読んだ後、この問題を解決するには、その Ruby 風バリアントが最も適切なアプローチであると判断しました。

ビジター パターンを使用すると、階層内の各ノードで実行するコードから、階層をたどるアルゴリズムを分離できます。map または inject/fold を使用してこれに対するより機能的なアプローチが可能です...しかし、演算子を再利用したいので、それらを別々のクラスに分割する方が簡単に思えました。

階層は各モデルに実装され、子を返す「子」メソッドを定義する必要があります。

以下は、さまざまな参照に基づいた私の実装です。これを宝石にまとめることができます。

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 に答える