2009-07-07 15 views
6

Obtuve una superclase Base y un grupo de clases derivadas, como Base::Number, Base::Color. Me gustaría poder utilizar esas clases secundarias como si heredé de decir Fixnum en el caso de Number.Herencia de clase de tipo herencia múltiple en ruby ​​

¿Cuál es la mejor manera de hacer esto, sin dejar de responder adecuadamente al is_a? Base?

Por lo tanto, debería ser capaz de hacer

Number.new(5) + Number.new(6) # => 11 
Number.new.is_a? Base   # => true 

Estoy pensando que podía mezclar la base y sobrescribir el is_a ?, kind_of? y instance_of? métodos, pero con suerte hay una manera más limpia.

Respuesta

13

Esto es realmente muy simple usando Ruby:

module Slugish 
    attr_accessor :slug 
    def loud_slug 
    "#{slug}!" 
    end 
end 

class Stringy < String 
    include Slugish 
end 

class Hashy < Hash 
    include Slugish 
end 

hello = Stringy.new("Hello") 
world = Stringy.new("World") 

hello.slug = "So slow" 
world.slug = "Worldly" 

hello.loud_slug  #=> "So slow!" 
world.loud_slug  #=> "Worldly!" 

hello.is_a?(Slugish) #=> true 
world.is_a?(Slugish) #=> true 

"#{hello} #{world}" #=> "Hello World" 

stuff = Hashy.new 
stuff[:hello] = :world 
stuff.slug = "My stuff" 
stuff.loud_stug  #=> "My stuff!" 
stuff.is_a?(Slugish) #=> true 
+1

oh wow, no sabía is_a? respondió 'true' para mixins, ¡e incluso funciona si el módulo incluido incluye otro módulo! Probablemente usaré esto luego, en lugar de reenviables. ¡Gracias! – cloudhead

+1

typo: debería ser 'world = Stringy.new (" World ")' – rampion

1

Creo que está utilizando la herencia de forma incorrecta si tiene clases completamente independientes como "Número" y "Color", todas derivadas de la misma clase base. Usaría composición en su lugar si necesitan acceso a las mismas rutinas (aunque no estoy seguro de por qué lo harían).

+0

el punto es que no son ajenos, que han compartido funcionalidad y necesito que todos sean reconocidos como base, frente a otros tipos de datos rubí. – cloudhead

+1

Los números y los colores no están relacionados. La herencia es una relación "es-a", no un "tiene-a". Usa la composición –

+0

La herencia no se trata de agrupar varias funciones auxiliares. –

3

¿Por qué insistes en usar is_a?/Kind_of? cuando responde_to? es una forma mucho más limpia de revisar las cosas? Desea que los objetos para implementar una interfaz/contrato no sean una subclase de cualquier superclase elegida arbitrariamente. Pero tal vez me falta algún tipo de requisito aquí.

Editar: Entiendo su razonamiento, pero a menudo conduce a un diseño OO/dinámico deficiente. Ya sea que estés haciendo algo como esto, lo que podría ser una idea aceptable en las clases de hojas pero en un marco debe ser resuelto con la herencia:

if a.is_a?(something) 
    #do something 
elif a.is_a?(something_else) 
    #do something else 
... 

o menos así:

if !a.is_a?(something) 
    #raise condition/return null/etc. 
endif 
...

creo que dejar que el código falle con no comprende la excepción en el idioma basado en el envío de mensajes es una decisión de diseño perfecta.

Como un problema adicional, ¿usa is_a? en lugar de respon_to? limita su capacidad para usar objetos de maqueta durante la prueba unitaria. Que puede ser un gran problema incluso para el código moderadamente complicado.

+2

respon_to? no siempre es más limpio, no es porque responde a un método que responderá a todas las demás llamadas que le envíe después. Entonces, revisar una vez si el tipo es correcto es mejor en este caso. – cloudhead

1

El equivalente de Ruby a la herencia múltiple es mixedins. Me parece que lo que quieres es que Base sea un módulo que se mezcle en varias clases.

+0

Sí, no sabía que los módulos incluidos se comportarían como superclases con respecto a is_a? - Eso hace que no sea un problema – cloudhead