C# 你如何在 Ruby 中实现多态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/137661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you do polymorphism in Ruby?
提问by FlySwat
In C#, I can do this:
在 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!";
}
}
Obviously, the output is (Slightly paraphrased):
显然,输出是(稍微解释一下):
- Woof
- Dog is Sleeping
- Meow
- Cat is Sleeping
- 纬
- 狗在睡觉
- 喵
- 猫在睡觉
Since C# is often mocked for its verbose type syntax, how do you handle polymorphism/virtual methods in a duck typed language such as Ruby?
由于 C# 经常因其冗长的类型语法而被嘲笑,您如何处理诸如 Ruby 之类的鸭子类型语言中的多态性/虚拟方法?
采纳答案by John Millikin
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.
免责声明:我有一年左右没有使用 Ruby,也没有在这台机器上安装它,所以语法可能完全错误。但概念是正确的。
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
}
回答by Brent.Longborough
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")
(我将保持原样,但“self.class.name”胜过“.to_s”)
回答by manveru
Using idiomatic Ruby
使用惯用的 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
回答by J?rg W Mittag
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 reallydifferent 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!
这是原始 C# 示例中的 12 行与 41 行(实际上,您可以使用集合初始值设定项减少 3 行)。不错!
回答by Mike Woodhouse
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..."
到目前为止,所有答案对我来说都很好。我想我只是提到整个继承的事情并不是完全必要的。暂时排除“睡眠”行为,我们可以使用鸭子类型实现整个预期结果,并且完全不需要创建 Animal 基类。谷歌搜索“鸭子打字”应该会产生任何数量的解释,所以在这里让我们说“如果它像鸭子一样走路,像鸭子一样嘎嘎叫......”
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.
“睡眠”行为可以通过使用 mixin 模块来提供,如 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
You know the rest...
其余的你都知道...
回答by zimbatm
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
回答by bitTnkr
A little variant of manveru's solution which dynamic create different kind of object based in an array of Class types. Not really different, just a little more clear.
manveru 解决方案的一个小变体,它基于类类型的数组动态创建不同类型的对象。没有什么不同,只是更清楚一点。
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
回答by itsnikolay
There's a method becomes
which implements a polymorphism (by coping all instance variables from given class to new one)
有一种becomes
实现多态的方法(通过将给定类的所有实例变量处理为新的)
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
and result is:
结果是:
Dog with name Spot becomes Cat
and makes a noise: Meow
----
Cat with name Tom becomes Cat
and makes a noise: Meow
----
A polymorphism could be useful to avoid
if
statement (antiifcampaign.com)If you use
RubyOnRails
becomes
method is already implemented:becomes
Quicktip: if you mix polymorphism with STIit brings you the most efficient combo to refactor your code
多态性可能有助于避免
if
声明(antiifcampaign.com)如果你使用的
RubyOnRails
becomes
方法已经实现:becomes
快速提示:如果您将多态性与STI混合使用,它将为您提供最有效的组合来重构您的代码
I wish it helped you
我希望它对你有帮助