سؤال

في 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

  • معلومات سريعة:إذا قمت بخلط تعدد الأشكال مع الأمراض المنقولة بالاتصال الجنسي فهو يوفر لك المجموعة الأكثر كفاءة لإعادة بناء التعليمات البرمجية الخاصة بك

أتمنى أن يكون قد ساعدك

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top