Domanda

In C #, posso farlo:

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

Ovviamente, l'output è (Leggermente parafrasato):

  • Woof
  • Il cane dorme
  • Meow
  • Il gatto dorme

Dato che C # viene spesso deriso per la sua sintassi di tipo prolisso, come gestisci i metodi polimorfismo / virtuali in un linguaggio tipizzato come anatra come Ruby?

È stato utile?

Soluzione

modifica: aggiunto altro codice per la domanda aggiornata

disclaimer: non uso Ruby da circa un anno e non l'ho installato su questa macchina, quindi la sintassi potrebbe essere completamente sbagliata. Ma i concetti sono corretti.


Esattamente allo stesso modo, con classi e metodi sostituiti:

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
}

Altri suggerimenti

Tutte le risposte finora mi sembrano abbastanza buone. Pensavo di menzionare che l'intera eredità non è del tutto necessaria. Escludendo il "sonno" comportamento per un momento, possiamo ottenere l'intero risultato desiderato usando la tipizzazione delle anatre e omettendo la necessità di creare una classe base di animali. Cercando su Google "digitando anatra" dovrebbe fornire un numero qualsiasi di spiegazioni, quindi per questo diciamo solo "se cammina come un'anatra e cigola come un'anatra ..."

Il " sleep " il comportamento potrebbe essere fornito utilizzando un modulo mixin, come Array, Hash e altre classi integrate di Ruby, incluso Enumerable. Non sto suggerendo che sia necessariamente migliore, solo un modo diverso e forse più idiomaticamente rubino di farlo.

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

Conosci il resto ...

Uso del rubino idiomatico

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

Partendo dalla risposta precedente, è così che potresti farlo?


Secondo taglio dopo il chiarimento:

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
}

(Lascerò così com'è, ma " self.class.name " vince su " .to_s ")

Il principio della tipizzazione anatra è proprio che l'oggetto deve rispondere ai metodi chiamati. Quindi qualcosa del genere potrebbe fare anche il trucco:

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 piccola variante della soluzione di manveru che crea dinamicamente diversi tipi di oggetti basati su una matrice di tipi di classe. Non molto diverso, solo un po 'più chiaro.

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

Ecco come lo scriverei:

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

Non è veramente diverso dalle altre soluzioni, ma questo è lo stile che preferirei.

Sono 12 linee contro le 41 linee (in realtà, puoi radere via 3 linee usando un inizializzatore di raccolta) dall'esempio C # originale. Non male!

Esiste un metodo diventa che implementa un polimorfismo (copiando tutte le variabili di istanza da una data classe a una nuova)

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 il risultato è:

Dog with name Spot becomes Cat
and makes a noise: Meow
----
Cat with name Tom becomes Cat
and makes a noise: Meow
----
  • Un polimorfismo potrebbe essere utile per evitare l'istruzione if ( antiifcampaign.com )

  • Se si utilizza RubyOnRails diventa il metodo è già implementato: diventa

  • Quicktip: se mescoli il polimorfismo con STI ti porta la combinazione più efficiente per il refactoring del tuo codice

Vorrei che ti aiutasse

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top