كيف تفعل تعدد الأشكال في روبي؟
-
02-07-2019 - |
سؤال
في 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!";
}
}
من الواضح أن الإخراج هو (أعيد صياغته قليلاً):
- اللحمة
- الكلب نائم
- مواء
- القطة نائمة
نظرًا لأن C# غالبًا ما يتم الاستهزاء بها بسبب تركيبها المطول، فكيف يمكنك التعامل مع تعدد الأشكال/الأساليب الافتراضية في لغة مكتوبة على شكل بطة مثل روبي؟
المحلول
يحرر:تمت إضافة المزيد من التعليمات البرمجية لسؤالك المحدث
تنصل:لم أستخدم 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
}
نصائح أخرى
جميع الإجابات حتى الآن تبدو جيدة جدًا بالنسبة لي.اعتقدت أنني سأذكر فقط أن موضوع الميراث برمته ليس ضروريًا تمامًا.باستثناء سلوك "النوم" للحظة، يمكننا تحقيق النتيجة المرجوة بالكامل باستخدام كتابة البطة وحذف الحاجة إلى إنشاء فئة أساسية للحيوان على الإطلاق.إن البحث في Google عن "كتابة البطة" يجب أن يؤدي إلى أي عدد من التفسيرات، لذا دعنا نقول هنا فقط "إذا كانت تمشي مثل البطة وتصدر صوتًا مثل البطة..."
يمكن توفير سلوك "السكون" باستخدام وحدة mixin، مثل Array وHash وفئات Ruby الأخرى المضمنة التي تتضمن Enumerable.أنا لا أقترح أنها أفضل بالضرورة، بل مجرد طريقة روبي مختلفة وربما أكثر اصطلاحًا للقيام بذلك.
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
أنت تعرف الباقي...
باستخدام روبي الاصطلاحية
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 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")
مبدأ كتابة البطة هو أن الكائن يجب أن يستجيب للطرق المطلوبة.لذا فإن شيئًا كهذا قد يفي بالغرض أيضًا:
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 الذي يقوم ديناميكيًا بإنشاء نوع مختلف من الكائنات بناءً على مجموعة من أنواع الفئات.ليس مختلفًا حقًا، فقط أكثر وضوحًا قليلًا.
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
هذه هي الطريقة التي سأكتبها:
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
ليست كذلك حقًا يختلف عن الحلول الأخرى، ولكن هذا هو النمط الذي أفضله.
هذا هو 12 سطرًا مقابل.الـ 41 سطرًا (في الواقع، يمكنك حذف 3 أسطر باستخدام أداة تهيئة المجموعة) من مثال C# الأصلي.ليس سيئًا!
هناك طريقة 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
والنتيجة هي:
Dog with name Spot becomes Cat
and makes a noise: Meow
----
Cat with name Tom becomes Cat
and makes a noise: Meow
----
قد يكون من المفيد تجنب تعدد الأشكال
if
إفادة (antiifcampaign.com)إذا كنت تستخدم
RubyOnRails
becomes
الطريقة مطبقة بالفعل:becomes
معلومات سريعة:إذا قمت بخلط تعدد الأشكال مع الأمراض المنقولة بالاتصال الجنسي فهو يوفر لك المجموعة الأكثر كفاءة لإعادة بناء التعليمات البرمجية الخاصة بك
أتمنى أن يكون قد ساعدك