Ruby类继承和增量定义

时间:2010-08-15 10:56:48

标签: ruby class inheritance

假设我们需要为树(或我们需要的其他一些对象来定义问题)定义一个公共类。由于我们的类结构可能非常复杂,我更喜欢在定义之后定义类方法。我们的公共课BaseTree和我们的特定课程Tree之一是

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

class Container
  class Tree < BaseTree; end
end

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

class BaseTree::BaseNode
  def initialize x
    p x
  end
end

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

Container::Tree::NodeA.new(1)
# => 1

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

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

然后它打破了NodeABaseNode !!

之间的继承
Container::Tree::NodeA.new(2)
# ~> -:30:in `initialize': wrong number of arguments(1 for 0) (ArgumentError)

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

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

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

或通过以下方式

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

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

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

class Container::Tree::NodeA
  def another_method; end
end

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

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

1 个答案:

答案 0 :(得分: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