Pergunta

Em C #, eu posso fazer isso:

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, a saída é (Um pouco parafraseado):

  • Woof
  • Dog está dormindo
  • Meow
  • gato está dormindo

Uma vez que C # é muitas vezes ridicularizado por sua sintaxe tipo detalhado, como você lida com o polimorfismo / métodos virtuais em uma linguagem digitada pato como Ruby?

Foi útil?

Solução

edit: adicionado mais código para sua pergunta atualizadas

IMPORTANTE: Eu não usei o Ruby em um ano ou assim, e não o tem instalado nesta máquina, de modo que a sintaxe pode ser totalmente errado. Mas os conceitos estão corretos.


A exata mesma maneira, com classes e métodos substituídos:

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
}

Outras dicas

Todas as respostas até agora parecem muito bons para mim. Eu pensei que eu tinha acabado de mencionar que a coisa toda herança não é totalmente necessário. Excluindo-se o comportamento de "dormir" por um momento, podemos conseguir todo o resultado desejado usando pato-digitação e omitindo a necessidade de criar uma classe base animal em tudo. Googling para "pato-digitando" deve render qualquer número de explicações, assim, por aqui, vamos apenas dizer "se ele anda como um pato e grasna como um pato ..."

O comportamento "sleep" poderia ser fornecido por meio de um módulo de mixin, como Array, Hash e outro Rubi classes built-in inclue Enumerable. Eu não estou sugerindo é necessariamente melhor, só um talvez mais idiomaticamente Rubi forma diferente e de fazê-lo.

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

Você sabe o resto ...

Usando o Ruby idiomática

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

Com base na resposta anterior, é assim que você pode fazê-lo?


Segundo corte após esclarecimento:

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
}

(Eu vou deixar isso como está, mas "self.class.name" vitórias sobre ".to_s")

O princípio da tipagem pato é apenas que o objeto tem de responder aos métodos chamados. Então algo assim pode fazer o truque demasiado:

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

Um pouco variante da solução da manveru que dinâmica criar diferentes tipos de objeto com base em uma variedade de tipos de classe. Não é realmente diferente, um pouco mais clara.

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

Isto é como eu ia escrever isso:

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

Não é realmente diferente das outras soluções, mas este é o estilo que eu preferiria.

Isso é 12 linhas vs. as 41 linhas (na verdade, você pode raspar 3 linhas usando um inicializador de coleção) do exemplo original C #. Não é mau!

Há um método becomes que implementa um polimorfismo (por enfrentar todas as variáveis ??de instância de determinada classe de novo)

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

e o resultado é:

Dog with name Spot becomes Cat
and makes a noise: Meow
----
Cat with name Tom becomes Cat
and makes a noise: Meow
----
  • Um polimorfismo pode ser útil para declaração if evitar ( antiifcampaign.com )

  • Se você usar RubyOnRails método becomes já está implementado: becomes

  • Quicktip: se você misturar polimorfismo com STI que traz a você a combinação mais eficiente para refatorar seu código

Eu gostaria que ajudou você

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top