variable tutorial classes ruby-on-rails ruby oop

ruby on rails - tutorial - Llamando a un método de subclase desde una superclase



ruby tutorial classes (4)

Prefacio: Esto está en el contexto de una aplicación Rails. La pregunta, sin embargo, es específica de Ruby.

Digamos que tengo un objeto Media .

class Media < ActiveRecord::Base end

Lo he extendido en unas pocas subclases:

class Image < Media def show # logic end end class Video < Media def show # logic end end

Desde dentro de la clase Media , quiero llamar a la implementación de show desde la subclase apropiada. Entonces, desde Media, si self es un Video , llamaría el método show del video. Si el self es en cambio una Image , llamaría el método show de la imagen.

Proveniente de un fondo de Java, lo primero que me vino a la cabeza fue ''crear un método abstracto en la superclase''. Sin embargo, he leído en varios lugares (incluido el desbordamiento de pila ) que los métodos abstractos no son la mejor manera de lidiar con esto en Ruby.

Con eso en mente, comencé a investigar encasillados y descubrí que esto también es una reliquia de Java, que creo que debo eliminar de mi mente cuando trato con Ruby.

Derrotado, comencé a codificar algo que se veía así:

def superclass_method # logic this_media = self.type.constantize.find(self.id) this_media.show end

He estado codificando en Ruby / Rails por un tiempo, pero como era la primera vez que probaba este comportamiento y los recursos existentes no respondían directamente a mi pregunta, quería recibir comentarios de desarrolladores más experimentados sobre cómo lograrlo. mi tarea.

Entonces, ¿cómo puedo llamar a la implementación de un método de una subclase de la superclase en Rails? ¿Hay una forma mejor que la que terminé (casi) implementando?


Buena pregunta, pero lo estás haciendo muy complicado. Tenga en cuenta algunos principios y todo debe quedar claro ...

  • Los tipos se resolverán dinámicamente, por lo que si un show existe en cualquier lugar de la jerarquía de clases del objeto en el momento en que se llama , Ruby lo encontrará y lo llamará. Le invitamos a que escriba las llamadas de método a cualquier cosa que pueda o no exista en el futuro, y es una sintaxis legal de ruby ​​que se analizará. Puede escribir una expresión que incluya una referencia a this_will_never_be_implemented y a nadie le importará a menos que realmente sea llamado.

  • Incluso en Java, solo hay un objeto real. Sí, puede tener un método en la superclase que está llamando a un método, pero es una instancia de la clase derivada (así como una instancia de la clase base) y, por lo tanto, puede contar con la nueva convocatoria.

  • En cierto sentido, cada clase de Ruby es una clase abstracta que contiene apéndices para cada método posible que pueda definirse en el futuro. Puede llamar a cualquier elemento sin calificadores de acceso en la clase base o en la clase derivada.

Si desea una implementación de superclase nula, puede definir una que no haga nada o que genere una excepción.

Actualización: Posiblemente, debería haber dicho "llamar a show como cualquier otro método" y dejarlo así, pero habiendo llegado hasta aquí quiero agregar: También puede implementar el show con la versión de herencia múltiple de Ruby: incluya SomeModule . Como obviamente estás interesado en el modelo de objetos de Ruby, puedes implementar tu atributo con una mezcla solo por diversión.


Como saben, tener una superclase sobre la funcionalidad de las subclases es un gran no-no, por lo que quería el método abstracto.

Lo que quieres hacer es definir show en tu superclase. Luego puede llamarlo en la superclase y la subclase llamará a su propia versión, pero la superclase no generará un error.

class Media < ActiveRecord::Base def show # This method should be overloaded in a subclass puts "Called from Media" end def do_something show end end class Image < Media def show puts "Called from Image" end end class Video < Media def show puts "Called from Video" end end i = Image.new i.do_something => Called from Image v = Video.new v.do_something => Called from Video


Respuesta simple Sólo llámalo . Ruby no tiene una verificación en tiempo de compilación por lo que no hay nadie para quejarse de que el show no esté definido en los Media . Si @example es una instancia de Image , cualquier llamada a @example.show se enviará a Image#show primero, donde sea que se realice. Solo si no aparece Image#show , la llamada se pasará a los Media , incluso si la llamada se originó a partir del código definido en los Media


Si desea llamar a show on self desde un método de Media , simplemente hágalo. Sin embargo, asegúrese de que self responde a la llamada de método.

class Media < ActiveRecord::Base def foo if self.respond_to?(:show) self.show else ... // * end end ... end

Para evitar la rama, implemente show en Medios, usando * como el cuerpo de show

class Media < ActiveRecord::Base def foo self.show end def show ... end end