我们如何在Ruby中进行多态?
时间:2020-03-06 14:45:53 来源:igfitidea点击:
在C#中,我可以这样做:
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!"; } }
显然,输出为(略述):
- 纬
- 狗在睡觉
- 喵
- 猫在睡觉
由于Cis经常因其冗长的类型语法而嘲笑,我们如何使用鸭子式语言(如Ruby)处理多态/虚拟方法?
解决方案
编辑:为我们更新的问题添加了更多代码
免责声明:我已经有大约一年没有使用Ruby了,也没有在该机器上安装Ruby,因此语法可能完全错误。但是这些概念是正确的。
与类和重写方法完全相同的方法:
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 }
在上一个答案的基础上,这是我们可能的做法吗?
澄清后的第二次切割:
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 }
(我将保持原样,但" self.class.name"将胜过" .to_s")
使用惯用的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
这就是我的写法:
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
它与其他解决方案并没有真正的不同,但这是我希望的样式。
与原始Cexample相比,这是12行与41行(实际上,我们可以通过使用集合初始化程序来减少3行)。不错!
到目前为止,所有答案对我来说都不错。我以为我只想提到整个继承并不是完全必要的。除了暂时的"睡眠"行为外,我们可以通过鸭式输入并完全不需要创建Animal基类来实现整体所需的结果。谷歌搜索"鸭型"应该给出许多解释,因此在这里我们只说"如果它像鸭子一样走路,而像鸭子一样嘎嘎..."
可以通过使用混合模块(例如Array,Hash和其他Ruby内置类(包括Enumerable))来提供"睡眠"行为。我并不是说它一定更好,这只是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
你知道其余的...
鸭子类型化的原则只是对象必须响应被调用的方法。所以类似的事情也可以解决这个问题:
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
manveru解决方案的一个小变体,它基于Class类型数组动态创建不同种类的对象。没什么不同,只是更清楚一点。
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