Ruby类继承和增量定义

And*_*rei 5 ruby inheritance class

让我们假设我们需要为树(或者我们需要的其他一些对象来定义一个公共类来解决问题).由于我们的类结构可能非常复杂,我更喜欢在定义之后定义类方法.我们共同的阶级BaseTree和我们的具体类之一Tree

class BaseTree
  class BaseNode; end
  class NodeA < BaseNode; end
end

class Container
  class Tree < BaseTree; end
end
Run Code Online (Sandbox Code Playgroud)

定义类结构后,我们#initialize为所有节点设置.

class BaseTree::BaseNode
  def initialize x
    p x
  end
end
Run Code Online (Sandbox Code Playgroud)

如果我们测试它,那么一切都很好

Container::Tree::NodeA.new(1)
# => 1
Run Code Online (Sandbox Code Playgroud)

但是,如果之后我们按以下方式添加方法

class Container::Tree::NodeA
  def some_method; end
end
Run Code Online (Sandbox Code Playgroud)

然后它打破了NodeA和之间的继承BaseNode!

Container::Tree::NodeA.new(2)
# ~> -:30:in `initialize': wrong number of arguments(1 for 0) (ArgumentError)
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我们必须明确定义它

class Container
  class Tree < BaseTree
    class NodeA < BaseNode; end # explicit inheritance
  end
end

class Container::Tree::NodeA
  def some_method; end
end
Run Code Online (Sandbox Code Playgroud)

或通过以下方式

class Container::Tree::NodeA < Container::Tree::BaseNode
  def some_method; end
end

class Container::Tree::NodeA < BaseTree::BaseNode
  def some_method; end
end
Run Code Online (Sandbox Code Playgroud)

最后一种方法只需要使用一次 - 我们第一次添加方法时,我们可以跳过父类以便以后定义

class Container::Tree::NodeA
  def another_method; end
end
Run Code Online (Sandbox Code Playgroud)

之后它工作正常,但我发现它非常麻烦,特别是如果有很多树类型和许多不同的节点.

有更优雅的方式来做这样的定义吗?

小智 2

在 ruby​​ 中组织代码的方式是使用模块作为命名空间,使用子类的类继承和继承行为。我不认为 ruby​​ 支持名称空间继承(这基本上就是您所说的 Tree 继承自 BaseTree 并将 NodeA 引用为 Tree::NodeA 所做的事情),因此出现了绑定不正确的奇怪边缘情况。

无论如何,我认为不存在需要按照呈现方式组织代码的有效场景。“正确”的方式是通过定义命名空间的模块和定义行为的类来组织它。

因此,定义一棵树的方法是要么简单地声明类,而不使用名称空间,要么使用一个名称空间来将它们与我有名称冲突的类区分开来:

module UserInterface
  class Container; end

  class Tree; end

  class BaseTree < Tree; end

  class BaseNode; end

  class NodeA < BaseNode; end
end


module DataStructures
  class Tree; end

  class RedBlackTree < Tree; end
end 
Run Code Online (Sandbox Code Playgroud)