假设我有两节课。一个班级,“父母”,有许多另一个班级“孩子”。这不是继承,我不希望父方法对子对象起作用。我想要的是子对象能够引用父对象,从中获取变量(child.parent.var)并调用修改父对象的父方法(child.parent.update
)。
我想要一个对象(可以被认为是一个孩子而不是孩子因为这不是继承)在初始化时传递对另一个对象的引用。我将它与父数据库中的父子关系进行比较,我们将信息存储在父数据库中,因此我们不必将其复制到每个子项上。
示例:
class Parent
attr_accessor :var
def initialize(num)
@var = num
end
def increase
@var += 1
end
end
class Child
attr_accessor :var, :parent
def initialize(parent, num)
@parent = parent
@var = num
end
def sum
@parent.increase
@parent.var + var
end
end
parent1 = Parent.new(1)
child1 = Child.new(parent1, 2)
child2 = Child.new(parent1, 3)
child1.parent.increase # update the parent variable
child2.parent.var # get the parent variable
上面的代码确实有效,但有没有更好的(更简洁,或更多ruby-esq)方法来实现这个目标?
非常感谢你的帮助/想法。
答案 0 :(得分:3)
这基本上是应该如何完成的:)虽然有一些可能的改进,取决于你真正想要实现的目标。
目前,您的Child
个实例在其外部接口上公开了对父级的访问权限(通过公共parent
访问者)。这通常违反了Law of Demeter,它指出对象应该只与他们的直接邻居交谈。从这个意义上说,parent
在通过子对象访问时是一个陌生人。
您可以通过隐藏父对象来改进设计:
class Child
extend Forwardable
def_delegator :@parent, :var, :parent_var
def_delegator :@parent, :increase
attr_accessor :var
def initialize(parent, num)
@parent = parent
@var = num
end
def sum
@parent.increase
@parent.var + var
end
end
在这里,我们使用Ruby的Forwardable模块来提供对客户端父级方法的访问。这使得这些方法成为您的Child类的单个公共接口的一部分。
parent = Parent.new(1)
child = Child.new(parent, 2)
child.var
# => 2
child.parent_var
# => 1
child.increase
# => 2
parent.var
# => 2
# ^^^^ the increase method was called on the parent object
从外部来看,方法转发并不重要,您可以稍后更改它而不会影响您的外部接口。
第二个改进可能是扩展您的Parent
课程以直接生成孩子:
class Parent
# ...
def child(num)
Child.new(self, num)
end
end
这通常称为Factory Method,即构建其他对象的方法。通过这种方式,您可以隐藏构建Child对象并将其附加到父对象的复杂性。
您可以将其称为
parent = Parent.new(1)
child = parent.child(2)