Pregunta

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, la salida es (ligeramente parafraseada):

  • Guau
  • El perro está durmiendo
  • Miau
  • El gato está durmiendo

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

¿Fue útil?

Solución

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

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


De la misma manera, con clases y métodos sobrescritos:

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
}

Otros consejos

Hasta ahora todas las respuestas me parecen bastante bien. Pensé que solo mencionaría que la herencia entera no es del todo necesaria. Excluyendo el " dormir " comportamiento por un momento, podemos lograr todo el resultado deseado utilizando la tipificación de pato y omitiendo la necesidad de crear una clase base Animal en absoluto. Buscar en Google para " tipografía de pato " debería dar cualquier número de explicaciones, así que aquí digamos "si camina como un pato y graznando como un pato ... "

El " dormir " el comportamiento podría proporcionarse mediante el uso de un módulo mixin, como Array, Hash y otras clases incorporadas de Ruby, incluso Enumerable. No estoy sugiriendo que sea necesariamente mejor, solo que es una forma diferente y quizás más idiomáticamente 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

Tú sabes el resto ...

Usando 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

Sobre la base de la respuesta anterior, ¿es así como podría 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 más de " .to_s ")

El principio de tipificación de pato es simplemente que el objeto tiene que responder a los métodos llamados. Así que algo así puede hacer el truco también:

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 cuya dinámica crea diferentes tipos de objetos basados ??en una matriz 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

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 frente a las 41 líneas (en realidad, puedes eliminar 3 líneas usando un inicializador de colección) del ejemplo original de C #. ¡No está mal!

Hay un método que se convierte en que implementa un polimorfismo (copiando todas las variables de instancia de una clase dada 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 si ( antiifcampaign.com )

  • Si utiliza RubyOnRails se convierte en ya está implementado: se convierte en

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

Ojalá te haya ayudado

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top