"Parent"、"Child" 类 在 Ruby 中(不是继承)
"Parent", "Child" Classes In Ruby (Not Inheritance)
假设我有两个 class。一个 class,"parent",还有许多 class "child"。这不是继承,我不希望父方法作用于子对象。我想要的是子对象能够引用父对象,从中获取变量(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)的方法来实现这个?
非常感谢您的 help/thoughts。
这基本上是应该如何完成的 :) 不过有一些可能的改进,具体取决于您实际想要实现的目标。
现在,您的 Child
实例在其外部接口上公开了对 parent 的访问(通过 public parent
访问器)。这通常违反了 Law of Demeter 规定 object 应该只与他们的直接邻居交谈。从这个意义上说,通过 child object.
访问时 parent
是一个陌生人
您可以通过隐藏 parent object:
来改进您的设计
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模块来提供从客户端访问parent的一些方法。这使得这些方法成为 Child class.
的单个 public 接口的一部分
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 以直接生成 children:
class Parent
# ...
def child(num)
Child.new(self, num)
end
end
这通常称为 Factory Method,即构建其他 object 的方法。有了这个,您可以隐藏构建 Child object 并将它们附加到 parent.
的复杂性
你可以这样称呼它
parent = Parent.new(1)
child = parent.child(2)
假设我有两个 class。一个 class,"parent",还有许多 class "child"。这不是继承,我不希望父方法作用于子对象。我想要的是子对象能够引用父对象,从中获取变量(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)的方法来实现这个?
非常感谢您的 help/thoughts。
这基本上是应该如何完成的 :) 不过有一些可能的改进,具体取决于您实际想要实现的目标。
现在,您的 Child
实例在其外部接口上公开了对 parent 的访问(通过 public parent
访问器)。这通常违反了 Law of Demeter 规定 object 应该只与他们的直接邻居交谈。从这个意义上说,通过 child object.
parent
是一个陌生人
您可以通过隐藏 parent object:
来改进您的设计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模块来提供从客户端访问parent的一些方法。这使得这些方法成为 Child class.
的单个 public 接口的一部分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 以直接生成 children:
class Parent
# ...
def child(num)
Child.new(self, num)
end
end
这通常称为 Factory Method,即构建其他 object 的方法。有了这个,您可以隐藏构建 Child object 并将它们附加到 parent.
的复杂性你可以这样称呼它
parent = Parent.new(1)
child = parent.child(2)