How do you do polymorphism in Ruby?

后端 未结 8 1337
灰色年华
灰色年华 2021-01-01 21:40

In C#, I can do this:

class Program
{
    static void Main(string[] args)
    {
        List animals = new List();

        anima         


        
相关标签:
8条回答
  • 2021-01-01 22:05

    The principle of duck typing is just that the object has to respond to the called methods. So something like that may do the trick too :

    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
    
    0 讨论(0)
  • 2021-01-01 22:11

    edit: added more code for your updated question

    disclaimer: I haven't used Ruby in a year or so, and don't have it installed on this machine, so the syntax might be entirely wrong. But the concepts are correct.


    The exact same way, with classes and overridden methods:

    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
    }
    
    0 讨论(0)
  • 2021-01-01 22:19

    Using idiomatic 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
    
    0 讨论(0)
  • 2021-01-01 22:21

    All the answers so far look pretty good to me. I thought I'd just mention that the whole inheritance thing is not entirely necessary. Excluding the "sleep" behaviour for a moment, we can achieve the whole desired outcome using duck-typing and omitting the need to create an Animal base class at all. Googling for "duck-typing" should yield any number of explanations, so for here let's just say "if it walks like a duck and quacks like a duck..."

    The "sleep" behaviour could be provided by using a mixin module, like Array, Hash and other Ruby built-in classes inclue Enumerable. I'm not suggesting it's necessarily better, just a different and perhaps more idiomatically Ruby way of doing it.

    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
    

    You know the rest...

    0 讨论(0)
  • 2021-01-01 22:23

    This is how I would write it:

    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
    

    It's not really different from the other solutions, but this is the style that I would prefer.

    That's 12 lines vs. the 41 lines (actually, you can shave off 3 lines by using a collection initializer) from the original C# example. Not bad!

    0 讨论(0)
  • 2021-01-01 22:25

    Building on the previous answer, is this how you might do it?


    Second cut after 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
    }
    

    (I'll leave this as is, but "self.class.name" wins over ".to_s")

    0 讨论(0)
提交回复
热议问题