Ruby类继承和增量定义

5

假设我们需要为树(或其他问题解决中所需的对象)定义一个通用类。由于我们的类结构可能非常复杂,因此我更喜欢在定义后定义类方法。 我们的通用类和其中的一个特定类是:

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

之后它可以正常工作,但我觉得这样做很繁琐,特别是如果有很多树种和许多不同的节点。

是否有更优雅的方法来定义它们?


也许可以执行 ping 核心来检查是否符合预期。 - rogerdpack
我不明白为什么你要使用类作为命名空间,我会期望在那里有模块。似乎存在绑定不匹配的问题,但我不理解这个问题。顺便说一下,你不是定义类方法,而是定义实例方法。 - mliebelt
1个回答

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 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接