ruby中的父/子关系?

ruby中的父/子关系?,ruby,Ruby,我想知道在ruby中创建双向父子关系的最佳方法是什么。例如,以下代码: class Bar def initialize(name) @name = name end end class Foo attr_accessor :children def initialize(names = %w(john ben maudy)) @children = names.map{|n| Bar.new(n)} end end 这样,从Foo实例到它的Bar子实例

我想知道在ruby中创建双向父子关系的最佳方法是什么。例如,以下代码:

class Bar
  def initialize(name)
    @name = name
   end
end

class Foo
  attr_accessor :children
  def initialize(names = %w(john ben maudy))
    @children = names.map{|n| Bar.new(n)}
  end
end
这样,从
Foo
实例到它的
Bar
子实例就很容易了。但它没有相反的方法。例如:

# Instanciates a Foo and get his first son
bar = Foo.new.children.first
# bar can't get to his parent. Essentially, I want 
bar.foo
到目前为止,我唯一的想法是在
Bar#new
方法中传递
self
,以保持
Bar
对象上的引用,但我希望避免这种情况。你能给我解释一个更好的方法吗

编辑

从谷歌我可以找到,这给了我行号。然而,我正在寻找一个对象引用,比行号更抽象一点

编辑2

你可以这样做

编辑3

这似乎是最合适的。如果有人能在没有宝石的情况下找到这样做的方法,我可能会用它来回答我自己的问题

这是一个示例,如果没有对组合的引用,就无法构建组件

这意味着您需要使用该组合对它们进行初始化(即将
self
传递到
Bar
实例)。这是这样做的,因为您需要对所有者的引用。您可以在之后设置它,例如
bar.foo=foo
,但它将实现一个更松散的链接,即聚合

如果我们没有收到推荐信,我们需要在某处找到它。我们可以使
Foo
成为一个单例,但它是一个反模式,因为它就像一个全局变量
Bar
实例可以向另一个对象请求其
Foo
的引用。如果有多个
Foo
实例,您需要使用一个id来标识它们,但这意味着
Bar
实例需要该id。那么,为什么不直接使用
Foo
实例的引用呢

总之,IMHO唯一好的解决方案是在构建新的
Bar
实例时传递
Foo
的引用。如果目的是尊重OO范式,那么隐藏重要的关系实现是个坏主意

使用Foo实例初始化Bar实例的代码

class Bar # Class of the component
  attr_reader :foo

  # the component must be initialized/built
  # with a ref to the composite foo
  def initialize(name, foo) 
    @name = name
    @foo = foo
   end
end

class Foo # Class of the composite
  attr_reader :children

  def initialize(names = %w(john ben maudy))
    @children = names.map do |n|
      Bar.new(n, self) # pass self to build the component
    end
  end
end

bar = Foo.new.children.first
bar.foo
关于调用方绑定的更新

这是一个使调用堆栈可访问的方法。在当前的情况下,它将在
Bar::initialized
方法中使用,以找到调用方组合,并要求它返回
self


然而,该项目需要改进。然后它就不是纯ruby了。

我认为您应该将foos传递到Bar的构造函数中,如下所示:

class Bar
  def initialize(name, parent)
    @name = name
    @parent = parent
   end
end

class Foo
  attr_accessor :children
  def initialize(names = %w(john ben maudy))
    @children = names.map{|n| Bar.new(n, self)}
  end
end
这样,每个条都会引用创建它的foo

如果你真的不想把foo传递到bar的构造函数中,你也可以做如下的事情,但我认为这不会给你带来太多好处

class Bar
  attr_accessor :foo
  def initialize(name)
    @name = name
   end
end

class Foo
  attr_accessor :children
  def initialize(names = %w(john ben maudy))
    @children = names.map{|n| Bar.new(n)}
  end
  def get_nth_child(n)
    bar = @children[n]
    bar.foo = self
    bar
  end
end
然后访问原始的foo,如:

Foo.new.get_nth_child(1).foo

Foo
继承
Bar
可以为您提供所需的访问权限。@user2276204但是
Foo
可以是
monkey
,而Bar可以是
banana
-这种关系很有意义,但您可能需要更改术语/实例变量名。这与OO意义上的父/子关系无关,可能会使事情变得混乱。@JimStewart请随意回答edit@fotanus我深入研究了调用者的绑定。为了使调用堆栈可访问,它需要。你不能用纯ruby来做这件事。请再次阅读我的问题:
到目前为止,我唯一的想法是在Bar中传递self#新方法,保留Bar对象上的引用,但这很难看。
@fotanus查看我的编辑。它会起作用,但我认为第一个选项更好。有趣的是,覆盖
[]
操作符可能更好?这不完全是我想要的,但无论如何都很有趣+1.创意。有趣的链接,谢谢-但是自我作为论点的解决方案,正如我所说的,我已经考虑过了。对不起,我错过了你的最后一个问题。我会更新我的答案。你反对通过赛尔夫吗?这是建立这种关系模型的正确和最好的方法。@toch我对此没有答案。然而,我并不认为这否定了这个问题——也许如果我们不必这样做,我们会感到更快乐?@toch我只是一个对玩具项目不满意的人。