visual una studio polimorfismo interfaces herencia hace ejemplos crear con como clases clase abstracta abstracción c# ruby polymorphism

c# - una - ¿Cómo se hace el polimorfismo en Ruby?



interfaces con c# (8)

En C #, puedo hacer esto:

class Program { static void Main(string[] args) { List<Animal> animals = new List<Animal>(); animals.Add(new Dog()); animals.Add(new Cat()); foreach (Animal a in animals) { Console.WriteLine(a.MakeNoise()); a.Sleep(); } } } public class Animal { public virtual string MakeNoise() { return String.Empty; } public void Sleep() { Console.Writeline(this.GetType().ToString() + " is sleeping."); } } public class Dog : Animal { public override string MakeNoise() { return "Woof!"; } } public class Cat : Animal { public override string MakeNoise() { return "Meow!"; } }

Obviamente, el resultado es (ligeramente parafraseado):

  • Guau
  • Perro está durmiendo
  • maullar
  • Cat está durmiendo

Dado que C # a menudo se burla de su sintaxis de tipo detallado, ¿cómo manejas el polimorfismo / los métodos virtuales en un lenguaje de tipo pato como Ruby?


Así es como lo escribiría:

class Animal def make_noise; '''' end def sleep; puts "#{self.class.name} is sleeping." end end class Dog < Animal; def make_noise; ''Woof!'' end end class Cat < Animal; def make_noise; ''Meow!'' end end [Dog.new, Cat.new].each do |animal| puts animal.make_noise animal.sleep end

No es realmente diferente de las otras soluciones, pero este es el estilo que preferiría.

Eso es 12 líneas vs. 41 líneas (en realidad, puedes cortar 3 líneas usando un inicializador de colección) del ejemplo original de C #. ¡No está mal!


Sobre la base de la respuesta anterior, ¿así es como puedes hacerlo?

Segundo corte después de la aclaración:

class Animal def MakeNoise raise NotImplementedError # I don''t remember the exact error class end def Sleep puts self.class.to_s + " is sleeping." end end class Dog < Animal def MakeNoise return "Woof!" end end class Cat < Animal def MakeNoise return "Meow!" end end animals = [Dog.new, Cat.new] animals.each {|a| puts a.MakeNoise a.Sleep }

(Dejaré esto como está, pero "self.class.name" gana a ".to_s")


Todas las respuestas hasta ahora se ven bastante bien para mí. Pensé que solo mencionaría que toda la herencia no es del todo necesaria. Excluyendo el comportamiento de "dormir" por un momento, podemos lograr el resultado deseado utilizando el pato-tipado y omitiendo la necesidad de crear una clase base Animal. Buscar en Google para "pato-mecanografiar" debería arrojar cualquier cantidad de explicaciones, así que para aquí solo digamos "si camina como un pato y grazna como un pato ..."

El comportamiento de "dormir" podría proporcionarse mediante el uso de un módulo de mixin, como Array, Hash y otras clases incorporadas de Ruby inclue Enumerable. No estoy sugiriendo que sea necesariamente mejor, solo una forma diferente y tal vez más idiomática de Ruby de hacerlo.

module Animal def sleep puts self.class.name + " sleeps" end end class Dog include Animal def make_noise puts "Woof" end end class Cat include Animal def make_noise puts "Meow" end end

Tu sabes el resto...


editar: agregó más código para su pregunta actualizada

descargo de responsabilidad: no he usado Ruby en un año más o menos, y no lo tengo instalado en esta máquina, por lo que la sintaxis puede ser completamente incorrecta. Pero los conceptos son correctos.

Exactamente de la misma manera, con clases y métodos anulados:

class Animal def MakeNoise return "" end def Sleep print self.class.name + " is sleeping./n" end end class Dog < Animal def MakeNoise return "Woof!" end end class Cat < Animal def MakeNoise return "Meow!" end end animals = [Dog.new, Cat.new] animals.each {|a| print a.MakeNoise + "/n" a.Sleep }


El principio de tipaje de pato es solo que el objeto tiene que responder a los métodos llamados. Entonces algo como eso también puede hacer el truco:

module Sleeping def sleep; puts "#{self} sleeps" end dog = "Dog" dog.extend Sleeping class << dog def make_noise; puts "Woof!" end end class Cat include Sleeping def to_s; "Cat" end def make_noise; puts "Meow!" end end [dog, Cat.new].each do |a| a.sleep a.make_noise end


Una pequeña variante de la solución de manveru que crea dinámicamente diferentes tipos de objetos basados ​​en una variedad de tipos de clase. No es realmente diferente, solo un poco más claro.

Species = [Dog, Cat] Species.each do |specie| animal = specie.new # this will create a different specie on each call of new print animal.MakeNoise + "/n" animal.Sleep end


Hay un método que implementa un polimorfismo (al hacer frente a todas las variables de instancia de una clase determinada a una nueva)

class Animal attr_reader :name def initialize(name = nil) @name = name end def make_noise '''' end def becomes(klass) became = klass.new became.instance_variables.each do |instance_variable| value = self.instance_variable_get(instance_variable) became.instance_variable_set(instance_variable, value) end became end end class Dog < Animal def make_noise ''Woof'' end end class Cat < Animal def make_noise ''Meow'' end end animals = [Dog.new(''Spot''), Cat.new(''Tom'')] animals.each do |animal| new_animal = animal.becomes(Cat) puts "#{animal.class} with name #{animal.name} becomes #{new_animal.class}" puts "and makes a noise: #{new_animal.make_noise}" puts ''----'' end

y el resultado es:

Dog with name Spot becomes Cat and makes a noise: Meow ---- Cat with name Tom becomes Cat and makes a noise: Meow ----

  • Un polimorfismo podría ser útil para evitar la declaración if ( antiifcampaign.com )

  • Si usa RubyOnRails becomes método ya implementado: se becomes

  • Sugerencia rápida: si mezclas el polimorfismo con STI te ofrece el combo más eficiente para refactorizar tu código

Ojalá te haya ayudado


Uso de Ruby idiomático

class Animal def sleep puts "#{self.class} is sleeping" end end class Dog < Animal def make_noise "Woof!" end end class Cat < Animal def make_noise "Meow!" end end [Dog, Cat].each do |clazz| animal = clazz.new puts animal.make_noise animal.sleep end