2008-09-26 29 views
14

सी # में, मैं यह कर सकता हूँ:रूबी में आप पॉलिमॉर्फिज्म कैसे करते हैं?

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!"; 
    } 
} 

जाहिर है, उत्पादन होता है (थोड़ा दूसरे शब्दों में बयान):

  • Woof
  • कुत्ता सो रही है
  • म्याऊ
  • बिल्ली सो रही है

चूंकि सी # को अक्सर अपने वर्बोज़ प्रकार सिंटैक्स के लिए मजाक किया जाता है, इसलिए आप रूबी जैसे बतख वाली भाषा में बहुरूपता/आभासी तरीकों को कैसे संभालेंगे?

+0

आपने "असली" बहुरूपता का उल्लेख किया है। "वास्तविक" के लिए आपकी परिभाषा क्या है: मैं आपको अपना देता हूं: http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming – OscarRyz

उत्तर

15

संपादित करें: अपने अद्यतन प्रश्न के लिए और अधिक कोड जोड़ा

अस्वीकरण: मैं एक साल या में रूबी का इस्तेमाल किया है नहीं है, और यह इस मशीन पर नहीं स्थापित किया है, इसलिए वाक्य रचना पूरी तरह से गलत हो सकता है। लेकिन अवधारणाएं सही हैं।


ठीक उसी तरह से, वर्गों और ओवरराइड तरीकों के साथ: पिछले जवाब पर

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

क्षमा करें, लेकिन रूबी का कौन सा संस्करण "कक्षा बिल्ली: पशु" है? क्या यह विरासत के लिए "<" नहीं है? –

+4

ब्रेंट: वह "पाइथन उपयोगकर्ता द्वारा याद किए जाने वाले रूबी" –

+1

तो, class.name आउटपुट पशु या कुत्ता होगा? मैं वास्तव में उत्सुक हूँ। – FlySwat

2

बिल्डिंग, यह कैसे आप यह कर सकता है?


स्पष्टीकरण के बाद दूसरा कटौती:

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 
} 

+1

'मेकनोइस' के विपरीत 'मेकनोइस'? 'रिटर्न 'का उपयोग करना? रूबी सम्मेलनों का पालन क्यों नहीं करें? –

+0

मुझे ऐसे सम्मेलन का पालन क्यों करना चाहिए जो मैं बेहद नापसंद करता हूं? आईएमएचओ, अंडरस्कोर बदसूरत है और पढ़ने के प्रवाह में बाधा डालता है; CamelCase पढ़ने के लिए बहुत आसान है। क्या आपने वास्तव में इसके लिए मुझे वास्तव में वोट दिया था? मेह मेरा जवाब है –

+1

@ ब्रेंट- यदि आप ऐसे कोड लिख रहे हैं जो अन्य लोग उपयोग करते हैं तो आपको एक सम्मेलन का पालन करना चाहिए (इसके बारे में आपकी राय के बावजूद)। वे कक्षा विधियों को संदर्भित करने के लिए CamelCase नामों को कक्षाओं और underscore_separated नामों का संदर्भ देने की उम्मीद करेंगे और सम्मेलन पर आपके विचारों के बारे में कुछ भी नहीं जान पाएंगे। यदि आप केवल पढ़ने के लिए कोड लिख रहे हैं तो यह एक बात है, लेकिन यदि अन्य लोग आपके कोड का उपयोग करने जा रहे हैं, तो कम से कम विस्फोट के सिद्धांत के साथ जाएं। – bta

10

(मैं इस रूप में है "self.class.name" छोड़ देंगे, लेकिन ".to_s" पर जीतता है) मुहावरेदार रूबी का उपयोग करना

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

आप सही हैं, और '' 'रिटर्न 'शून्य' डालते हैं, इसलिए बाहरी 'puts'' प्रिंट ("# {nil} \ n") 'के बराबर, एक प्रिंटलाइन के बराबर 'प्रिंट' करेगा, जो 'प्रिंट (" \ n ")' जैसा ही है। मैंने अपने आउटपुट में पिछली नई लाइन नहीं देखी, इसके बारे में खेद है। – manveru

+0

यह जानवरों को रखना चाहिए। Make_noise; animal.sleep', जानवर नहीं रखता है। नींद – YoTengoUnLCD

0

यह मैं इसे कैसे लिखना होता है:

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 

यह वास्तव में अन्य समाधानों से अलग नहीं है, लेकिन यह वह शैली है जिसे मैं पसंद करूंगा।

मूल सी # उदाहरण से 41 लाइनों (वास्तव में, आप संग्रह प्रारंभकर्ता का उपयोग करके 3 लाइनों को बंद कर सकते हैं) बनाम 12 लाइनें हैं। बुरा नहीं!

22

सभी उत्तर अब तक मेरे लिए बहुत अच्छे लग रहे हैं। मैंने सोचा कि मैं बस उल्लेख करता हूं कि पूरी विरासत चीज पूरी तरह जरूरी नहीं है। एक पल के लिए "नींद" व्यवहार को छोड़कर, हम बतख-टाइपिंग का उपयोग करके पूरे वांछित परिणाम प्राप्त कर सकते हैं और पशु आधार वर्ग बनाने की आवश्यकता को छोड़ सकते हैं। "बतख-टाइपिंग" के लिए गुगलिंग में किसी भी प्रकार की स्पष्टीकरण पैदा होनी चाहिए, इसलिए यहां केवल यह कहना है कि "अगर यह एक बतख और बतख जैसे बतख की तरह चलता है ..."

"नींद" व्यवहार का उपयोग करके प्रदान किया जा सकता है एक मिश्रण मॉड्यूल, जैसे ऐरे, हैश और अन्य रूबी अंतर्निर्मित कक्षाएं अंकुरित हैं। मैं यह सुझाव नहीं दे रहा हूं कि यह आवश्यक रूप से बेहतर है, बस इसे करने का एक अलग और शायद अधिक मूर्खतापूर्ण रूबी तरीका।

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 

आप बाकी को जानते हैं ...

+2

मिश्रण के लिए +1-इसे प्रबंधित करने की बजाय सामान्य कार्यक्षमता में। जबकि दोनों विधियां काम करती हैं, यह "इसे करने का रूबी तरीका" है (इस विशेष उदाहरण के लिए)। – bta

+0

यह मजाकिया है कि क्रुबी में, यह लगभग विरासत के बराबर है: मॉड्यूल पशु सहित कुत्ते के सुपरक्लास को पशु होने के लिए सेट किया जाता है, और कुत्ते के पिछले सुपरक्लास पशु के सुपरक्लास होने के लिए सेट करता है। हालांकि यह काम करता है, और "इसे करने का रूबी तरीका" हो सकता है, किसी को ध्यान रखना चाहिए कि यह विरासत से बहुत कम कुशल है: क्रुबी प्रत्येक वर्ग के लिए मॉड्यूल की एक प्रति बनाता है (ऊपर बताए गए कारण के लिए)। – YoTengoUnLCD

1

बतख टाइपिंग का सिद्धांत यह है कि ऑब्जेक्ट को बुलाए गए तरीकों का जवाब देना है। तो ऐसा ही कुछ भी काम कर सकता है:

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 
1

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 
0

एक विधि 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)

  • आप का उपयोग करते हैं RubyOnRailsbecomes पद्धति पहले से ही लागू किया गया है: becomes

  • Quicktip: यदि आप STI साथ बहुरूपता मिश्रण यह आप सबसे कुशल कॉम्बो लाता है अपने कोड

मैं refactor करने के लिए इच्छा है कि यह आपकी मदद करे

संबंधित मुद्दे