2010-08-15 16 views
5

Supongamos que necesitamos definir una clase común para árboles (u otros objetos que necesitamos para resolver un problema). Dado que nuestra estructura de clases puede ser bastante compleja, prefiero definir métodos de clase después de su definición. Nuestra clase común BaseTree y una de nuestras clases específicas Tree sonHerencia de clase Ruby y definición incremental

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

class Container 
    class Tree < BaseTree; end 
end 

Después de definir la estructura de clases, nos propusimos #initialize para todos los nodos.

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

Si lo probamos, entonces todo está bien

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

Sin embargo, si después de eso le sumamos un método de la siguiente manera

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

entonces se rompe la herencia entre NodeA y BaseNode !!

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

Con el fin de solucionar este problema, tenemos que definir explícitamente

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

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

o mediante la siguiente manera

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

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

La última forma tiene que ser utilizado sólo una vez - la primera vez que agregamos un método, y podemos omitir la clase padre para definiciones posteriores

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

Después de eso funciona bien, pero me resulta bastante engorroso, especialmente si hay muchos tipos de árboles y muchos nodos diferentes.

¿Hay alguna manera más elegante de hacer tales definiciones?

+0

tal vez ping core para ver si esto se espera – rogerdpack

+0

No entiendo por qué usas clases para espacios de nombres, esperaría tener módulos allí. Parece que hay un desajuste de enlaces, pero no entiendo el problema aquí. Por cierto, no defines métodos de clase, defines métodos de instancia. – mliebelt

Respuesta

2

La forma en que debe organizar el código en ruby ​​es mediante el uso de módulos como espacio de nombres y herencia de clase para subclases y comportamiento heredado. No creo que Ruby admita la herencia del espacio de nombres (que es básicamente lo que estás haciendo al decir Tree hereda de BaseTree y hace referencia a NodeA como Tree :: NodeA), y por lo tanto este extraño caso donde las vinculaciones no son correctas.

En cualquier caso, no creo que haya un escenario válido en el que necesite organizar el código de la forma en que lo presente. La forma "adecuada" sería organizarlo a través de módulos que definen el espacio de nombres y las clases que definen el comportamiento.

Por lo tanto, la forma en que uno vaya definiendo un árbol como tal está bien simplemente declarar las clases únicamente, sin espacios de nombres, o con un espacio de nombres que los diferencia de clases que mi tiene un nombre choque:

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 
Cuestiones relacionadas