Frage

In C #, ich kann 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 der Ausgang (Ein wenig paraphrasiert):

  • Woof
  • Hund Schläft
  • Meow
  • Katze schläft

Da C # oft für seine ausführliche Art Syntax verspottet wird, wie gehen Sie Polymorphismus / virtuelle Methoden in einer Ente typisierte Sprache wie Ruby?

War es hilfreich?

Lösung

edit: mehr Code für Ihre aktualisierte Frage hinzugefügt

Disclaimer: Ich habe nicht Rubin in einem Jahr verwendet oder so, und habe es nicht auf diesem Computer installiert, so dass die Syntax möglicherweise völlig falsch sein. Aber die Begriffe korrekt sind.


Genau die gleiche Art und Weise, mit Klassen und überschriebenen Methoden:

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
}

Andere Tipps

Alle Antworten so weit schauen ziemlich gut zu mir. Ich dachte, ich würde nur erwähnen, dass das ganze Erbe, was nicht unbedingt notwendig ist. Ohne den „Schlaf“ Verhalten für einen Moment können wir das ganze gewünschte Ergebnis mit Ente-Eingabe erreichen und die Notwendigkeit, das Weglassen überhaupt ein Tier Basisklasse zu erstellen. für „duck-typing“ Googeln eine beliebige Anzahl von Erklärungen ergeben sollte, so denn hier sagen wir einfach „wenn es wie eine Ente geht und quakt wie eine Ente ...“

Das „Schlaf“ Verhalten durch die Verwendung eines mixin Modul zur Verfügung gestellt werden könnte, wie Array, Hash und anderen Ruby-integrierte Klassen inclue Enumerable. Ich schlage nicht vor, es ist unbedingt besser, nur eine andere und vielleicht mehr idiomatisch Ruby-Art und Weise tun.

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

Sie kennen den Rest ...

Mit idiomatischem Ruby-

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

Auf der Grundlage der vorherigen Antwort, das ist, wie Sie könnte es tun?


Zweiter Schnitt nach der Klärung:

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
}

(Ich werde diese lassen wie es ist, aber "self.class.name" gewinnt ".to_s")

Das Prinzip der Ente Typisierung ist nur, dass das Objekt auf die aufgerufenen Methoden zu reagieren. So etwas wie das kann den Trick auch:

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

Eine kleine Variante der manveru-Lösung, die eine dynamische andere Art von Objekt in einer Reihe von Klassentypen basieren erstellen. Nicht wirklich anders, nur ein wenig klarer.

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

Dies ist, wie ich es schreiben würde:

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 von den anderen Lösungen, aber das ist der Stil, den ich lieber.

Das ist 12 Zeilen gegen die 41 Linien (tatsächlich, können Sie 3 Zeilen abrasieren durch eine Auflistungsinitialisierer verwendet wird) aus dem ursprünglichen C # Beispiel. Nicht schlecht!

Es gibt eine Methode becomes, die einen Polymorphismus implementiert (durch alle Instanzvariablen von bestimmten Klasse zu neuen Bewältigungs)

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 nützlich sein könnte, zu vermeiden if Aussage ( antiifcampaign.com )

  • Wenn Sie RubyOnRails becomes Methode wird bereits umgesetzt: becomes

  • Quicktip: Wenn Sie Polymorphismus mit STI es Sie bringt die effizienteste Combo Code

  • Refactoring

Ich wünsche es Ihnen geholfen,

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top