Ruby class inheritance and incremental definition
Let's assume that we need to define a common class for trees (or some other objects we need to have in order to solve a problem). Since our class structure can be quite complex, I prefer to define class methods after its definition. Our common class BaseTree
and one of our specific classes Tree
are
class BaseTree
class BaseNode; end
class NodeA < BaseNode; end
end
class Container
class Tree < BaseTree; end
end
After defining the class structure, we set #initialize
for all nodes.
class BaseTree::BaseNode
def initialize x
p x
end
end
If we test it, then everything is fine
Container::Tree::NodeA.new(1)
# => 1
However, if after that we add a method in the following way
class Container::Tree::NodeA
def some_method; end
end
then it breaks the inheritance between NodeA
and BaseNode
!!
Container::Tree::NodeA.new(2)
# ~> -:30:in `initialize': wrong number of arguments(1 for 0) (ArgumentError)
In order to fix this, we have to define it explicitly
class Container
class Tree < BaseTree
class NodeA < BaseNode; end # explicit inheritance
end
end
class Container::Tree::NodeA
def some_method; end
end
or by the following way
class Container::Tree::NodeA < Container::Tree::BaseNode
def some_method; end
end
class Container::Tree::NodeA < BaseTree::BaseNode
def some_method; end
end
The last way needs to be used only once - the first time we add a method, and we can skip the parent class for later definitions
class Container::Tree::NodeA
def another_method; end
end
After that it works fine, but I find it quite cumbersome, especially if there are a lot of tree types and many different nodes.
Is there a more elega开发者_高级运维nt way to do such definitions?
The way you should organize code in ruby is by using modules as namespace, and class inheritance for subclasses and inheriting behavior. I don't think ruby supports namespace inheritance (which is basically what you are doing by saying Tree inherits from BaseTree and referencing NodeA as Tree::NodeA), and hence this weird edge case where the bindings are not correct.
In any case, I don't think there's a valid scenario in which you need to organize the code the way you present it. The 'proper' way would be organizing it through modules defining the namespace, and classes defining behavior.
So, the way one would go by defining a tree as such is either simply declare the classes only, without namespaces, or with a namespace that differentiates them from classes that my have a name clash:
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
精彩评论