ruby中的父/子关系?
我想知道在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子实例
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我只是一个对玩具项目不满意的人。