14 Stimmen

Wie kann man Polymorphismus in Ruby einsetzen?

In C# kann ich dies tun:

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

Offensichtlich ist das Ergebnis (leicht umschrieben):

  • Wuff
  • Der Hund schläft
  • Miau
  • Die Katze schläft

Da C# oft für seine ausführliche Typsyntax verspottet wird, wie gehen Sie mit Polymorphismus/virtuellen Methoden in einer duck typed Sprache wie Ruby um?

1voto

bitTnkr Punkte 31

Eine kleine Variante der Lösung von manveru, die dynamisch verschiedene Arten von Objekten aus einem Array von Klassentypen erstellt. Nicht wirklich anders, nur ein wenig mehr klar.

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

0voto

Jörg W Mittag Punkte 349574

Ich würde es so schreiben:

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

Es ist nicht wirklich anders als die anderen Lösungen, aber das ist der Stil, den ich bevorzugen würde.

Das sind 12 Zeilen im Vergleich zu den 41 Zeilen (tatsächlich können Sie 3 Zeilen einsparen, indem Sie einen Auflistungsinitialisierer verwenden) aus dem ursprünglichen C#-Beispiel. Nicht schlecht!

0voto

itsnikolay Punkte 16062

Es gibt eine Methode becomes die einen Polymorphismus implementiert (indem alle Instanzvariablen der gegebenen Klasse in die neue kopiert werden)

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

und das Ergebnis ist:

Dog with name Spot becomes Cat
and makes a noise: Meow
----
Cat with name Tom becomes Cat
and makes a noise: Meow
----
  • Ein Polymorphismus könnte nützlich sein, um Folgendes zu vermeiden if Anweisung ( antiifcampaign.com )

  • Wenn Sie RubyOnRails becomes Methode ist bereits implementiert: becomes

  • Kleiner Tipp: Wenn Sie Polymorphismus mit STI die effizienteste Kombination zur Umstrukturierung Ihres Codes

Ich wünschte, es würde Ihnen helfen

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X