रूबी में शामिल और विस्तारित करने के बीच क्या अंतर है?


415

बस रूबी मेटाप्रोग्रामिंग के आसपास मेरा सिर हो रही है। मिक्सर / मॉड्यूल हमेशा मुझे भ्रमित करने का प्रबंधन करते हैं।

  • शामिल करें : लक्ष्य वर्ग में उदाहरण विधियों के रूप में निर्दिष्ट मॉड्यूल विधियों में घोला जा सकता है
  • विस्तार : लक्ष्य वर्ग में कक्षा विधियों के रूप में निर्दिष्ट मॉड्यूल विधियों में मिश्रण

तो क्या यह प्रमुख अंतर है या यह एक बड़ा अजगर है? जैसे

module ReusableModule
  def module_method
    puts "Module Method: Hi there!"
  end
end

class ClassThatIncludes
  include ReusableModule
end
class ClassThatExtends
  extend ReusableModule
end

puts "Include"
ClassThatIncludes.new.module_method       # "Module Method: Hi there!"
puts "Extend"
ClassThatExtends.module_method            # "Module Method: Hi there!"

इस लिंक को भी देखें: juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby
Donato

जवाबों:


249

आपने जो कहा है वह सही है। हालाँकि इससे कहीं अधिक है।

आप एक वर्ग है, तो Klazzऔर मॉड्यूल Mod, सहित Modमें Klazzके उदाहरण देता है Klazzके लिए उपयोग Modकी तरीकों। या आप कक्षा के तरीकों को देने के Klazzसाथ विस्तार कर सकते हैं । लेकिन इसके साथ ही आप एक मनमानी वस्तु का विस्तार कर सकते हैं । इस मामले में व्यक्तिगत वस्तु को एक ही वर्ग के साथ अन्य सभी वस्तुओं के तरीके मिलते हैं।Mod KlazzModo.extend ModModo


324

विस्तार - निर्दिष्ट मॉड्यूल के तरीकों और लक्ष्य के मेटाक्लास (यानी एकल वर्ग) जैसे स्थिरांक जोड़ता है

  • अगर आप कॉल करते हैं Klazz.extend(Mod), तो अब Klazz में मॉड के तरीके (वर्ग विधियों के रूप में) हैं
  • अगर आप कॉल करते हैं obj.extend(Mod), तो अब obj में Mod के तरीके (उदाहरण के तरीके) हैं, लेकिन obj.classउन तरीकों में से किसी अन्य उदाहरण को नहीं जोड़ा गया है।
  • extend एक सार्वजनिक तरीका है

शामिल करें - डिफ़ॉल्ट रूप से, यह निर्दिष्ट मॉड्यूल के तरीकों को लक्ष्य मॉड्यूल / वर्ग में उदाहरण के तरीकों के रूप में मिलाता है। जैसे

  • यदि आप कॉल करते हैं class Klazz; include Mod; end;, तो अब Klazz के सभी उदाहरणों में मॉड के तरीकों (उदाहरण के तरीकों) तक पहुंच है
  • include एक निजी तरीका है, क्योंकि इसे कंटेनर वर्ग / मॉड्यूल के भीतर से बुलाया जाना है।

हालांकि , मॉड्यूल बहुत बार बंदर-पैचिंग द्वारा व्यवहार को ओवरराइड include करते हैंincluded विधि । यह विरासत रेल कोड में बहुत प्रमुख है। Yehuda Katz से अधिक जानकारी

इसके includeडिफ़ॉल्ट व्यवहार के बारे में अधिक जानकारी , यह मानते हुए कि आपने निम्न कोड चलाया है

class Klazz
  include Mod
end
  • यदि मॉड पहले से ही Klazz, या इसके पूर्वजों में से एक में शामिल है, तो शामिल विवरण का कोई प्रभाव नहीं है
  • इसमें क्लाज़ में मॉड की स्थिरांक भी शामिल हैं, जब तक वे टकराते नहीं हैं
  • यह मॉड के मॉड्यूल वैरिएबल, जैसे @@fooया@@bar
  • यदि चक्रीय शामिल हैं तो ArgumentError को बढ़ाता है
  • कॉलर के तत्काल पूर्वज के रूप में मॉड्यूल को शामिल करता है (यानी यह मॉड को Klazz.ancestors में जोड़ता है, लेकिन मॉड को Klazz.superclass.superclass.superclass की श्रृंखला में नहीं जोड़ा जाता है। इसलिए, superKlazz # foo में कॉल करने से पहले जाँच करें। Klazz की असली सुपरक्लास की फू विधि। विवरण के लिए रूबीस्पीक देखें।)

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


22
मुझे पता है कि यह बहुत पुरानी पोस्ट है, लेकिन उत्तर की स्पष्टता मुझे टिप्पणी करने से रोक नहीं सकती है। एक अच्छी व्याख्या के लिए बहुत बहुत धन्यवाद।
मोहम्मदनाउल्ला

2
@anwar जाहिर है, लेकिन अब मैं टिप्पणी कर सकता हूं और मैं फिर से लेख को खोजने में कामयाब रहा। यह यहां उपलब्ध है: aaronlasseigne.com/2012/01/17/explaining-include-and-extend और मुझे अभी भी लगता है कि स्कीमा समझ को बहुत आसान बनाती है
systho

1
इस प्रतिक्रिया में बड़ी जीत यह है कि उपयोग के आधार पर extendतरीकों को वर्ग या उदाहरण के तरीकों के रूप में कैसे लागू किया जा सकता है । Klass.extend= वर्ग विधियाँ, objekt.extend= उदाहरण विधियाँ। मैं हमेशा (गलत तरीके से) क्लास के तरीकों से आया extend, और उदाहरण से include
फ्रैंक कोहल

16

यह सही है।

पर्दे के पीछे, वास्तव में परिशिष्ट के लिए एक उपनाम है , जो (डॉक्स से):

रूबी का डिफ़ॉल्ट क्रियान्वयन इस मॉड्यूल के स्थिरांक, विधियों और मॉड्यूल चर को जोड़ने के लिए है, यदि इस मॉड्यूल को पहले से हीModule या इसके किसी पूर्वज में नहीं जोड़ा गया है।


4

जब आप includeकिसी वर्ग में मॉड्यूल रखते हैं, तो मॉड्यूल विधियों को उदाहरण के तरीकों के रूप में आयात किया जाता है ।

हालाँकि, जब आप extendकिसी वर्ग में मॉड्यूल रखते हैं, तो मॉड्यूल विधियों को वर्ग विधियों के रूप में आयात किया जाता है ।

उदाहरण के लिए, यदि हमारे पास एक मॉड्यूल Module_testनिम्नानुसार परिभाषित है:

module Module_test
  def func
    puts "M - in module"
  end
end

अब, includeमॉड्यूल के लिए। यदि हम Aनिम्नानुसार वर्ग को परिभाषित करते हैं:

class A
  include Module_test
end

a = A.new
a.func

उत्पादन होगा: M - in module

अगर हम लाइन की जगह include Module_testके साथ extend Module_testऔर कोड को फिर से चलाने के लिए, हम निम्न त्रुटि प्राप्त: undefined method 'func' for #<A:instance_num> (NoMethodError)

करने के लिए विधि कॉल बदल रहा a.funcहै A.func, उत्पादन में परिवर्तन M - in module:।

उपरोक्त कोड निष्पादन से, यह स्पष्ट है कि जब हम includeएक मॉड्यूल होते हैं, तो इसकी विधियाँ उदाहरण के तरीके बन जाती हैं और जब हम extendएक मॉड्यूल होते हैं, तो इसकी विधियाँ कक्षा की विधियाँ बन जाती हैं ।


3

अन्य सभी उत्तर अच्छे हैं, जिसमें रूबीस्पेक के माध्यम से खुदाई करने के लिए टिप भी शामिल है:

https://github.com/rubyspec/rubyspec/blob/master/core/module/include_spec.rb

https://github.com/rubyspec/rubyspec/blob/master/core/module/extend_object_spec.rb

उपयोग मामलों के लिए:

यदि आप शामिल हैं ClassThatIncludes मॉड्यूल ReusableModule , तो विधियाँ, स्थिरांक, वर्ग, सबमॉड्यूल और अन्य घोषणाएँ संदर्भित हो जाती हैं।

यदि आप मॉड्यूल ReusableModule के साथ वर्ग ClassThatExtends का विस्तार करते हैं , तो विधियों और स्थिरांक की प्रतिलिपि बनाई जाती है । जाहिर है, अगर आप सावधान नहीं हैं, तो आप गतिशील रूप से डुप्लिकेट परिभाषाओं द्वारा बहुत सारी मेमोरी बर्बाद कर सकते हैं।

यदि आप ActiveSupport :: चिंता का उपयोग करते हैं, तो .included () कार्यक्षमता आपको सीधे शामिल वर्ग को फिर से लिखने देती है। एक चिंता के अंदर मॉड्यूल ClassMethods को शामिल वर्ग में विस्तारित (कॉपी) किया जाता है ।


1

मैं तंत्र को भी समझाना चाहूंगा क्योंकि यह काम करता है। अगर मैं सही नहीं हूं तो कृपया सही करें।

जब हम उपयोग includeकरते हैं तो हम अपनी कक्षा से एक मॉड्यूल में एक लिंकेज जोड़ रहे हैं जिसमें कुछ विधियाँ होती हैं।

class A
include MyMOd
end

a = A.new
a.some_method

ऑब्जेक्ट्स में विधियाँ नहीं हैं, केवल क्लैसेस और मॉड्यूल हैं। इसलिए जब यह aमेसेंज प्राप्त करता है तो some_methodयह खोज विधि some_methodको a'ईगन क्लास' में , फिर Aकक्षा में और फिर से लिंक में शुरू करता हैA क्लास मॉड्यूल अगर कुछ (रिवर्स ऑर्डर में, अंतिम शामिल जीत) होते हैं।

जब हम उपयोग extendकरते हैं तो हम ऑब्जेक्ट के eigen क्लास में एक मॉड्यूल से लिंकेज जोड़ रहे हैं। इसलिए यदि हम A.new.extend (MyMod) का उपयोग करते हैं तो हम अपने मॉड्यूल से A के उदाहरण eigen क्लास या a'क्लास में लिंकेज जोड़ रहे हैं । और अगर हम A.extend (MyMod) का उपयोग करते हैं, तो हम A (ऑब्जेक्ट्स, क्लास भी ऑब्जेक्ट हैं) eigenclass से लिंकेज जोड़ रहे हैं A'

इसलिए विधि खोज पथ aनिम्नानुसार है: a => a '=> लिंक किए गए मॉड्यूल को' क्लास => ए।

वहाँ भी एक पूर्वसर्ग विधि है जो लुकअप पथ को बदल देती है:

a => a '=> पूर्वनिर्धारित modulesto A => A => इसमें A से मॉड्यूल शामिल है

मेरी खराब इंग्लिश के लिए माफ़ कीजिये।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.