नेस्टेड कक्षाओं और मॉड्यूल में नेस्टेड कक्षाओं का उपयोग कब करें?


144

जब उपवर्गों और मॉड्यूल का उपयोग करने के लिए मैं बहुत परिचित हूं, लेकिन हाल ही में मैं इस तरह से नेस्टेड कक्षाएं देख रहा हूं:

class Foo
  class Bar
    # do some useful things
  end
end

साथ ही वर्गों में मॉड्यूल जैसे नेस्टेड हैं:

module Baz
  class Quux
    # more code
  end
end

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

क्या कोई व्यक्ति उन तकनीकों के उदाहरण / लिंक प्रदान कर सकता है, जिनका उपयोग कब / क्यों किया जाएगा?

जवाबों:


140

अन्य ओओपी भाषाओं में आंतरिक वर्ग होते हैं, जिन्हें ऊपरी स्तर के वर्ग से जुड़े बिना त्वरित नहीं किया जा सकता है। उदाहरण के लिए, जावा में,

class Car {
    class Wheel { }
}

केवल Carकक्षा में विधियाँ बना सकती हैं Wheel

रूबी का वह व्यवहार नहीं है।

रूबी में,

class Car
  class Wheel
  end
end

से भिन्न है

class Car
end

class Wheel
end

केवल वर्ग Wheelबनाम के नाम पर Car::Wheel। नाम में यह अंतर प्रोग्रामर को स्पष्ट कर सकता है कि सामान्य Car::Wheelवर्ग के विपरीत, वर्ग केवल एक कार पहिया का प्रतिनिधित्व कर सकता है। रूबी में नेस्टिंग क्लास परिभाषाएँ प्राथमिकता का विषय है, लेकिन यह इस अर्थ में एक उद्देश्य प्रदान करता है कि यह दो वर्गों के बीच एक अनुबंध को अधिक मजबूती से लागू करता है और ऐसा करने में उनके और उनके उपयोगों के बारे में अधिक जानकारी प्राप्त करता है।

लेकिन रूबी दुभाषिया के लिए, यह केवल नाम में अंतर है।

आपके दूसरे अवलोकन के लिए, मॉड्यूल के अंदर नेस्टेड कक्षाओं को आमतौर पर कक्षाओं को नाम देने के लिए उपयोग किया जाता है। उदाहरण के लिए:

module ActiveRecord
  class Base
  end
end

से भिन्न है

module ActionMailer
  class Base
  end
end

हालांकि यह केवल मॉड्यूल के अंदर नेस्टेड कक्षाओं का उपयोग नहीं है, यह आमतौर पर सबसे आम है।


5
@rubyprince, मुझे यकीन नहीं है कि आपके बीच संबंध स्थापित करने का क्या मतलब है Car.newऔर Car::Wheel.new। आपको निश्चित रूप से रूबी में एक Carऑब्जेक्ट को इनिशियलाइज़ करने के लिए किसी ऑब्जेक्ट को इनिशियलाइज़ करने की आवश्यकता नहीं है Car::Wheel, लेकिन Carक्लास को लोड किया जाना चाहिए और Car::Wheelप्रयोग करने योग्य होना चाहिए।
पैन थॉमकोस

30
@Pan, आप Java आंतरिक कक्षाओं और रूबी कक्षाओं को नामांकित कर रहे हैं । एक गैर-स्थैतिक जावा नेस्टेड क्लास को एक आंतरिक वर्ग कहा जाता है और यह केवल बाहरी वर्ग के उदाहरण के भीतर ही मौजूद होता है। एक छिपा हुआ क्षेत्र है जो बाहरी संदर्भों की अनुमति देता है। रूबी आंतरिक वर्ग बस नामांकित है और किसी भी तरह से संलग्न वर्ग के लिए "बाध्य" नहीं है। यह जावा स्टैटिक (नेस्टेड) क्लास के बराबर है । हां, जवाब में बहुत सारे वोट हैं लेकिन यह पूरी तरह से सही नहीं है।
डिजिटलरॉस

7
मुझे नहीं पता कि इस उत्तर को 60 उत्थान कैसे मिले, अकेले ओपी द्वारा स्वीकार किया गया। यहाँ शाब्दिक रूप से एक भी सत्य कथन नहीं है। रूबी में नेस्ट या न्यूजपेपर जैसी नेस्टेड क्लास नहीं हैं। वहाँ के बीच पूरी तरह से कोई संबंध नहीं जो भी है Carऔर Car::Wheel। मॉड्यूल (और इस प्रकार कक्षाएं) स्थिरांक के लिए बस नाम स्थान हैं, रूबी में एक नेस्टेड वर्ग या नेस्टेड मॉड्यूल जैसी कोई चीज नहीं है।
जोर्ग डब्ल्यू मित्तग

4
दोनों के बीच एकमात्र अंतर निरंतर संकल्प है (जो कि शाब्दिक है, और इस प्रकार स्पष्ट रूप से अलग है क्योंकि दोनों स्निपक्स शाब्दिक रूप से भिन्न हैं)। हालाँकि, इसमें शामिल वर्गों के विषय में दोनों के बीच बिल्कुल कोई अंतर नहीं है। बस दो पूरी तरह से असंबंधित वर्ग हैं। अवधि। रूबी के पास नेस्टेड / इनर क्लास नहीं है। नेस्टेड वर्गों की आपकी परिभाषा सही है, लेकिन यह केवल रूबी पर लागू नहीं होता है, जैसा कि आप तुच्छ परीक्षण कर सकते हैं Car::Wheel.new:। बूम। मैंने सिर्फ एक Wheelऑब्जेक्ट का निर्माण किया है, जो किसी Carऑब्जेक्ट के अंदर नेस्टेड नहीं है ।
जोर्ग डब्ल्यू मित्तग

10
पूरी टिप्पणी के सूत्र को पढ़े बिना यह पोस्ट बेहद भ्रामक है।
नाथन

50

रूबी में, एक नेस्टेड क्लास को परिभाषित करना एक मॉड्यूल में एक क्लास को परिभाषित करने के समान है। यह वास्तव में वर्गों के बीच एक संघ को मजबूर नहीं करता है, यह सिर्फ स्थिरांक के लिए एक नाम स्थान बनाता है। (कक्षा और मॉड्यूल नाम स्थिरांक हैं।)

स्वीकृत उत्तर किसी भी चीज़ के बारे में सही नहीं था। 1 नीचे दिए गए उदाहरण में, मैं कभी-कभी संलग्न मौजूदा वर्ग के उदाहरण के बिना lexically संलग्न वर्ग का एक उदाहरण बनाता हूं।

class A; class B; end; end
A::B.new

मॉड्यूल के लिए फायदे समान हैं: इनकैप्सुलेशन, ग्रुपिंग कोड केवल एक ही स्थान पर उपयोग किया जाता है, और कोड को जहां इसे उपयोग किया जाता है, के करीब रखा जाता है। एक बड़ी परियोजना में एक बाहरी मॉड्यूल हो सकता है जो प्रत्येक स्रोत फ़ाइल में बार-बार होता है और इसमें बहुत अधिक वर्ग परिभाषाएँ होती हैं। जब विभिन्न रूपरेखा और पुस्तकालय कोड सभी ऐसा करते हैं, तो वे संघर्ष के अवसर को कम करते हुए, शीर्ष स्तर पर केवल एक नाम का योगदान करते हैं। प्रोसिक, सुनिश्चित होने के लिए, लेकिन यही कारण है कि उनका उपयोग किया जाता है।

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

आप स्क्रिप्ट के लिए भी सामान्य पैटर्न का उपयोग कर सकते हैं, जहाँ नाम स्थान की बहुत ज़रूरत नहीं है, बस मज़े और अभ्यास के लिए ...

#!/usr/bin/env ruby

class A
  class Realwork_A
    ...
  end
  class Realwork_B
    ...
  end

  def run
    ...
  end

  self
end.new.run

15
कृपया, बहुत कृपया, इसे एक आंतरिक वर्ग न कहें। यह। वर्ग Bहै नहीं अंदर वर्ग Aलगातार B अंदर वर्ग namespaced है A, लेकिन वहाँ बिल्कुल वस्तु द्वारा संदर्भित बीच कोई रिश्ता नहीं है B(जो इस मामले में सिर्फ एक वर्ग होता है) और वर्ग द्वारा संदर्भित A
जोर्ग डब्ल्यू मित्तग

2
ठीक है, "आंतरिक" शब्दावली हटा दी गई। अच्छी बात। उन लोगों के लिए जो ऊपर दिए गए तर्क का पालन नहीं कर रहे हैं, विवाद का कारण यह है कि जब आप ऐसा कुछ करते हैं, तो कहते हैं, जावा, आंतरिक वर्ग की वस्तुओं (और यहां मैं शब्द का उपयोग कर रहा हूं) में एक संदर्भ शामिल है बाहरी वर्ग और बाहरी उदाहरण चर को आंतरिक वर्ग विधियों द्वारा संदर्भित किया जा सकता है। जब तक आप उन्हें कोड के साथ लिंक नहीं करते तब तक रूबी में ऐसा कुछ नहीं होता। और आप जानते हैं, यदि वह कोड ahem, a एन्क्लोजिंग क्लास में मौजूद था, तो मुझे यकीन है कि आप बार को एक आंतरिक वर्ग
DigitalRoss

1
मेरे लिए यह एक ऐसा वक्तव्य है जो मुझे एक मॉड्यूल और एक वर्ग के बीच निर्णय लेने में सबसे अधिक मदद करता है: You can't call new on a module.- इसलिए मूल शब्दों में अगर मैं सिर्फ कुछ वर्गों को नाम देना चाहता हूं और वास्तव में बाहरी "वर्ग" का उदाहरण बनाने की आवश्यकता नहीं है , तो मैं एक बाहरी मॉड्यूल का उपयोग करता हूं। लेकिन अगर मैं रैपिंग / एक्सटर्नल "क्लास" के एक उदाहरण को इंस्टेंट करना चाहता हूं, तो मैं इसे एक मॉड्यूल के बजाय एक क्लास बनाऊंगा। कम से कम यह मेरे लिए समझ में आता है।
फायरड्रगन

@ फ़ायरड्रैगन या एक अन्य उपयोग का मामला यह हो सकता है कि आप एक ऐसा वर्ग चाहते हैं जो एक फैक्टरी हो, जो उपवर्गों से प्राप्त हो, और आपका कारखाना उपवर्गों के उदाहरण बनाने के लिए ज़िम्मेदार हो। उस स्थिति में, आपके फैक्टरी नहीं एक मॉड्यूल क्योंकि आप एक मॉड्यूल से विरासत में नहीं कर सकते हैं, तो यह एक माता पिता के वर्ग है कि आप इन्स्तांत नहीं है (और कर सकते हैं 'नाम स्थान' यह बच्चों अगर तुम चाहते हो, की तरह एक मॉड्यूल की तरह) हो सकता है
rmcsharry

15

आप शायद अपनी कक्षाओं को एक मॉड्यूल में समूहित करने के लिए इसका उपयोग करना चाहते हैं । एक नाम स्थान की चीज़ की तरह।

उदाहरण के लिए ट्विटर रत्न इसे प्राप्त करने के लिए नेमस्पेस का उपयोग करता है:

Twitter::Client.new

Twitter::Search.new

इसलिए मॉड्यूल के तहत दोनों Clientऔर Searchवर्ग रहते हैं Twitter

यदि आप स्रोतों की जांच करना चाहते हैं, तो दोनों वर्गों के लिए कोड यहां और यहां पाया जा सकता है

उम्मीद है की यह मदद करेगा!


3
ट्विटर रत्न अपडेट किया गया लिंक: github.com/sferik/twitter/tree/master/lib/twitter
kode

6

रुबी में 2.5 से पहले नेस्टेड वर्गों और नेस्टेड मॉड्यूल के बीच एक और अंतर है कि अन्य उत्तर यह कवर करने में विफल रहे कि मुझे लगता है कि यहां उल्लेख किया जाना चाहिए। यह लुकअप प्रक्रिया है।

संक्षेप में: 2.5 से पहले के रूबी में शीर्ष स्तर की निरंतर खोज के कारण, Objectयदि आप नेस्टेड कक्षाओं का उपयोग करते हैं , तो रूबी आपके नेस्टेड क्लास को गलत जगह ( विशेष रूप से) में देख सकती है।

रुबी में 2.5 से पहले:
नेस्टेड क्लास स्ट्रक्चर: मान लीजिए कि आपके पास Xनेस्टेड क्लास है Y, या X::Y। और फिर आपके पास एक शीर्ष स्तरीय वर्ग भी है जिसका नाम भी है Y। अगर X::Yलोड नहीं है, तो निम्न होता है जब आप कहते हैं X::Y:

नहीं मिला करने के बाद Yमें X, रूबी के पूर्वजों में उसे ढूंढने की कोशिश करेंगे X। जबसेXएक वर्ग है और एक मॉड्यूल नहीं है, इसके पूर्वज हैं, जिनके बीच हैं [Object, Kernel, BasicObject]। इसलिए, यह देखने के लिए कोशिश करता है Yमें Objectजहां यह इसे सफलतापूर्वक पाता है,।

फिर भी यह शीर्ष स्तर है Yऔर नहीं X::Y। आपको यह चेतावनी मिलेगी:

warning: toplevel constant Y referenced by X::Y


नेस्टेड मॉड्यूल संरचना: मान लीजिए कि पिछले उदाहरण Xमें एक मॉड्यूल है और एक वर्ग नहीं है।

एक मॉड्यूल केवल पूर्वज के रूप में ही है: X.ancestorsउत्पादन करेगा [X]

इस मामले में, रूबी Yके पूर्वजों में से एक में देखने के लिए सक्षम नहीं Xहोगा और एक फेंक देगा NameError। रेल (या ऑटोलेडिंग के साथ कोई अन्य ढांचा) X::Yउसके बाद लोड करने की कोशिश करेगी ।

: अधिक जानकारी के लिए यह लेख देखें https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/

में रूबी 2.5:
शीर्ष स्तर निरंतर लुकअप हटाया गया।
आप इस बग का सामना करने के डर के बिना नेस्टेड कक्षाओं का उपयोग कर सकते हैं।


3

पिछले उत्तरों के अलावा: रूबी में मॉड्यूल एक वर्ग है

$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object

11
आपको यह कहना अधिक सटीक होगा कि 'रूबी एक मॉड्यूल है'!
टिम डिगिन्स

2
रूबी में सब कुछ एक वस्तु हो सकती है, लेकिन मॉड्यूल को एक वर्ग सही नहीं लगता है: irb (मुख्य): 005: 0> Class.ancestors.reverse => [BasicObject, कर्नेल, ऑब्जेक्ट, मॉड्यूल, क्लास
चाड M

और यहाँ हम "की परिभाषा पर आते हैं"
ahnbizcad

ध्यान दें कि मॉड्यूल को तत्काल नहीं किया जा सकता है। यानी, मॉड्यूल से ऑब्जेक्ट्स बनाना संभव नहीं है। इसलिए मॉड्यूल, कक्षाओं के विपरीत, एक विधि नहीं है new। इसलिए यद्यपि आप कह सकते हैं कि मॉड्यूल एक वर्ग (निचला) हैं, वे कक्षा (अपरकेस) के समान नहीं हैं :)
rmcsharry
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.