"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)