Question

En C #, je peux faire ceci:

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!";
    }
}

Évidemment, le résultat est (légèrement paraphrasé):

  • Woof
  • Le chien dort
  • Miaou
  • le chat dort

Etant donné que la syntaxe de type verbose est souvent utilisée pour maitriser C #, comment gérez-vous les méthodes de polymorphisme / virtuelles dans un langage typé canard tel que Ruby?

Était-ce utile?

La solution

modifier: ajout de code supplémentaire pour votre question mise à jour

disclaimer: Je n'ai pas utilisé Ruby depuis un an et je ne l'ai pas installé sur cette machine. La syntaxe est donc peut-être totalement fausse. Mais les concepts sont corrects.

De la même manière, avec les classes et les méthodes substituées:

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
}

Autres conseils

Toutes les réponses à ce jour me semblent plutôt bonnes. Je pensais simplement mentionner que la question de l'héritage n'est pas entièrement nécessaire. À l'exclusion du " sommeil " comportement pendant un moment, nous pouvons obtenir l’ensemble des résultats souhaités en tapant des canards et en éliminant la nécessité de créer une classe de base d’Animal. Googler pour "dactylographie" devrait donner toutes sortes d’explications, alors pour ici, disons simplement "s’il marche comme un canard et que les charlatans sont comme un canard ..."

Le "sommeil" le comportement pourrait être fourni en utilisant un module mixin, comme Array, Hash et d'autres classes intégrées à Ruby, notamment Enumerable. Je ne dis pas que c'est nécessairement mieux, mais juste une façon différente et peut-être plus idiomatique de faire Ruby.

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

Vous connaissez le reste ...

Utilisation de Ruby idiomatique

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

En vous basant sur la réponse précédente, est-ce ainsi que vous pourriez le faire?

Deuxième coupure après clarification:

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
}

(Je laisse cela tel quel, mais "self.class.name" l'emporte sur ".to_s")

Le principe du dactylographie est simplement que l’objet doit répondre aux méthodes appelées. Donc, quelque chose comme ça peut aussi faire l'affaire:

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

Une petite variante de la solution de manveru permettant de créer différents types d’objets en fonction d’un tableau de types de classe. Pas vraiment différent, juste un peu plus clair.

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

Voici comment je l'écrirais:

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

Ce n'est pas vraiment différent des autres solutions, mais c'est le style que je préférerais.

Cela correspond à 12 lignes contre 41 (en fait, vous pouvez éliminer 3 lignes à l’aide d’un initialiseur de collection) de l’exemple C # original. Pas mal!

Il existe une méthode devient qui implémente un polymorphisme (en copiant toutes les variables d'instance d'une classe à une nouvelle)

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

et le résultat est:

Dog with name Spot becomes Cat
and makes a noise: Meow
----
Cat with name Tom becomes Cat
and makes a noise: Meow
----
  • Un polymorphisme pourrait être utile pour éviter une instruction si ( antiifcampaign.com )

  • Si vous utilisez RubyOnRails , devient , la méthode est déjà implémentée: devient

  • Petite astuce: si vous mélangez le polymorphisme avec STI , il vous apporte la combinaison la plus efficace pour refactoriser votre code

Je souhaite que cela vous aide

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top