आपको निजी / आंतरिक वर्ग का उपयोग कब करना चाहिए?


21

स्पष्ट करने के लिए, मैं जो पूछ रहा हूं वह है

public class A{
    private/*or public*/ B b;
}

बनाम

public class A{
    private/*or public*/ class B{
        ....
    }
}

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


2
इसका उत्तर भाषा और कोर पुस्तकालयों द्वारा दी जाने वाली सुविधाओं पर निर्भर करेगा। C # भाषा मानकर, इन्हें StyleCop द्वारा चलाने का प्रयास करें। मुझे पूरा यकीन है कि आपको इस वर्ग को अपनी फ़ाइल में अलग करने के बारे में एक चेतावनी मिलेगी। इसका मतलब है कि MSFT में पर्याप्त लोग सोचते हैं कि आपको उन उदाहरणों में से किसी एक का उपयोग करने की आवश्यकता नहीं है जो आपने उपयोग किया है।
जॉब

यदि एकेडमिक उदाहरण पर्याप्त नहीं हैं, तो एक ठोस उदाहरण क्या होगा?

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

जवाबों:


20

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


2
इस तरह से मैं उनका उपयोग करता हूं। यदि एक वर्ग एक कार्यात्मक दृष्टिकोण से है, तो एक वर्ग के निजी कार्यान्वयन विस्तार के अलावा कुछ भी नहीं है, तो इसे उसी तरह से घोषित किया जाना चाहिए, जिस तरह एक निजी पद्धति या क्षेत्र होगा। कचरे के साथ नाम स्थान को प्रदूषित करने का कोई कारण नहीं है जो कभी भी कहीं और इस्तेमाल होने वाला नहीं है।
एरोन

9

मान लीजिए कि आप एक पेड़, एक सूची, एक ग्राफ आदि का निर्माण कर रहे हैं। आपको बाहरी दुनिया के नोड या सेल के आंतरिक विवरण को क्यों उजागर करना चाहिए?

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

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

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


5

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

उदाहरण के लिए, यदि आपको दो असंबंधित वर्गों के डेटा की सूची को बांधने की आवश्यकता है:

public class UiLayer
{
    public BindLists(List<A> as, List<B> bs)
    {
        var list = as.ZipWith(bs, (x, y) => new LayerListItem { AnA = x, AB = y});
        // do stuff with your new list.
    }

    private class LayerListItem
    {
        public A AnA;
        public B AB;
    }
}

यदि आपके आंतरिक वर्ग का उपयोग किसी अन्य वर्ग द्वारा किया जाता है, तो आपको इसे अलग रखना चाहिए। यदि आपके आंतरिक वर्ग में कोई तर्क है, तो आपको इसे अलग रखना चाहिए।

मूल रूप से, मुझे लगता है कि वे आपके डेटा ऑब्जेक्ट्स में छेद करने के लिए बहुत अच्छे हैं, लेकिन उन्हें बनाए रखना मुश्किल है, अगर उन्हें वास्तव में तर्क देना है, क्योंकि आपको यह जानना होगा कि उन्हें कहाँ देखना है अगर आपको इसे बदलने की आवश्यकता है।


2
C # मानकर, क्या आप यहां केवल टुपल्स का उपयोग नहीं कर सकते?
जॉब

3
@ जॉब ज़रूर, लेकिन कभी-कभी tuple.ItemXकोड अस्पष्ट बना देता है।
लास एस्पेहोल्ट

2
@ जोब यूप, लेस्स्पेसहोल्ट को एक अधिकार मिला। मैं इसके बजाय {string शीर्षक का एक आंतरिक वर्ग देखता हूँ; स्ट्रिंग विवरण; } टुपल <string, string> से।
एड जेम्स

उस बिंदु पर उस वर्ग को अपनी फ़ाइल में रखने का कोई मतलब नहीं होगा?
जॉब

नहीं, यदि आप वास्तव में केवल इसका उपयोग कर रहे हैं तो कुछ डेटा को एक साथ जोड़ने के लिए संक्षेप में एक कार्य को प्राप्त करने के लिए जो मूल वर्ग के रीमिट से बाहर नहीं जाता है। कम से कम, मेरी राय में नहीं!
एड जेम्स

4
  • कुछ भाषा में आंतरिक कक्षाएं (उदाहरण के लिए जावा) में उनके युक्त वर्ग के ऑब्जेक्ट के लिए एक टाई होती है और वे अपने सदस्यों का उपयोग बिना योग्यता के कर सकते हैं। उपलब्ध होने पर, यह अन्य भाषा सुविधाओं का उपयोग करके उन्हें फिर से लागू करने की तुलना में स्पष्ट है।

  • अन्य भाषा में नेस्टेड कक्षाएं (उदाहरण के लिए C ++) में ऐसी टाई नहीं होती है। आप बस वर्ग द्वारा प्रदत्त स्कूपिंग और एक्सेसिबिलिटी कंट्रोल का उपयोग कर रहे हैं।


3
वास्तव में जावा में दोनों हैं।
जोकिम सॉर

3

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


क्या यह मुद्दा कहीं दस्तावेज है?
गनत

Downvoter: क्या मेरा दावा गलत है?
केविन क्लाइन

1
मैंने अस्वीकृत कर दिया क्योंकि आपके उत्तर में विवरण का अभाव है, इसलिए नहीं कि यह गलत है। विवरण का अभाव आपके दावे को सत्यापित करने के लिए कठिन बनाता है। यदि आप उस मुद्दे पर और अधिक जोड़ते हैं, तो मैं संभवत: फिर से आगे बढ़ना चाहूंगा, क्योंकि आपकी जानकारी काफी दिलचस्प लग रही है और उपयोगी हो सकती है
gnat

1
@gnat: मैंने थोड़ा शोध किया और जबकि यह एक सर्वविदित सत्य है, मुझे Java HotSwap की सीमाओं पर एक निश्चित संदर्भ नहीं मिला।
केविन क्लाइन

हम Skeptics.SE पर नहीं हैं :) सिर्फ कुछ संदर्भ करेंगे, यह निश्चित नहीं होना चाहिए
gnat

2

निजी स्थिर आंतरिक वर्ग के लिए उपयोग में से एक मेमो पैटर्न है। आप सभी डेटा को निजी कक्षा में याद रखने की आवश्यकता रखते हैं और इसे किसी फ़ंक्शन से ऑब्जेक्ट के रूप में वापस करते हैं। बाहर कोई नहीं कर सकता (प्रतिबिंब, deserialization, स्मृति निरीक्षण के बिना ...) इसे देखो / इसे संशोधित करें, लेकिन वह इसे आपकी कक्षा में वापस दे सकता है और यह उसकी स्थिति को पुनर्स्थापित कर सकता है।


2

एक निजी आंतरिक वर्ग का उपयोग करने का एक कारण यह हो सकता है क्योंकि आप जिस एपीआई का उपयोग कर रहे हैं, उसे किसी विशेष वर्ग से विरासत की आवश्यकता होती है, लेकिन आप अपने बाहरी वर्ग के उपयोगकर्ताओं को उस वर्ग के ज्ञान का निर्यात नहीं करना चाहते हैं। उदाहरण के लिए:

// async_op.h -- someone else's api.
struct callback
{
    virtual ~callback(){}
    virtual void fire() = 0;
};

void do_my_async_op(callback *p);



// caller.cpp -- my api
class caller
{
private :
    struct caller_inner : callback
    {
        caller_inner(caller &self) : self_(self) {}
        void fire() { self_.do_callback(); }
        caller &self_;
    };

    void do_callback()
    {
        // Real callback
    }

    caller_inner inner_;

public :
    caller() : inner_(*this) {}

    void do_op()
    {
        do_my_async_op(&inner_);
    }
};

इसमें do_my_async_op को पास होने के लिए टाइप कॉलबैक की एक वस्तु की आवश्यकता होती है। इस कॉलबैक में एक सार्वजनिक सदस्य फ़ंक्शन हस्ताक्षर है जिसे एपीआई उपयोग करता है।

जब do_op () को आउटर_क्लास से पुकारा जाता है, तो यह निजी आंतरिक वर्ग के एक उदाहरण का उपयोग करता है जो अपने लिए पॉइंटर के बजाय आवश्यक कॉलबैक वर्ग से विरासत में मिला है। बाहरी वर्ग के पास बाहरी वर्ग के निजी do_callback फ़ंक्शन फ़ंक्शन में कॉलबैक को शंट करने के सरल उद्देश्य के लिए बाहरी वर्ग का संदर्भ होता है।

इसका लाभ यह है कि आप सुनिश्चित हैं कि कोई भी संभवतः सार्वजनिक "फायर ()" सदस्य फ़ंक्शन को कॉल नहीं कर सकता है।


2

गहराई में सी # में जॉन स्कीट के अनुसार, एक नेस्टेड क्लास का उपयोग करना पूरी तरह से आलसी धागा-सुरक्षित सिंगलटन (फिफ्थ संस्करण देखें) को लागू करने का एकमात्र तरीका है (.NET 4 तक)।


1
यह प्रारंभ डिमांड धारक मुहावरा , जावा में यह भी निजी स्थिर भीतरी वर्ग की आवश्यकता है। यह JMM FAQ में अनुशंसित है , JCiP में ब्रायन गोएट्ज ने 16.4 और जोसुआ बलोच ने जावाऑन 2008 में और अधिक प्रभावी जावा (पीडीएफ) "स्टेटिक ऑन अ स्टैटिक ऑन अ स्टैटिक फील्ड ..."
gnat

1

निजी और आंतरिक कक्षाओं का उपयोग एन्कैप्सुलेशन के स्तर को बढ़ाने और कार्यान्वयन विवरणों को छिपाने के लिए किया जाता है।

C ++ में, एक निजी वर्ग के अलावा, एक ही अवधारणा को वर्ग cpp के अनाम नामस्थान को लागू करके प्राप्त किया जा सकता है। यह कार्यान्वयन विवरण को छिपाने / निजीकरण करने के लिए अच्छी तरह से कार्य करता है।

यह एक आंतरिक या निजी वर्ग के रूप में एक ही विचार है, लेकिन एनकैप्सुलेशन के एक भी बड़े स्तर पर क्योंकि यह फ़ाइल के संकलन इकाई के बाहर पूरी तरह से अदृश्य है। इसका कुछ भी हेडर फ़ाइल में नहीं दिखता है या बाहरी रूप से कक्षा की घोषणा में दिखाई देता है।


-1 पर कोई रचनात्मक प्रतिक्रिया?
हाईवेलॉन

1
मैंने नीचा नहीं देखा, लेकिन मुझे लगता है कि आप वास्तव में इस सवाल का जवाब नहीं दे रहे हैं: आप निजी / आंतरिक वर्ग का उपयोग करने का कोई कारण नहीं दे रहे हैं। आप बस यह बता रहे हैं कि यह कैसे काम करता है और सी ++ में एक समान काम कैसे किया जाता है
साइमन बर्गोट

वास्तव में। मुझे लगा कि यह मेरे और अन्य उत्तरों (कार्यान्वयन विवरणों को छिपाने, इनकैप्सुलेशन के स्तर में वृद्धि, आदि) द्वारा स्पष्ट था, लेकिन मैं कुछ स्पष्ट करने की कोशिश करूंगा। धन्यवाद @Simon।
हाईवेलॉन

1
अच्छा संपादन। और कृपया इस तरह की प्रतिक्रिया के कारण अपराध न करें। एसओ नेटवर्क शोर अनुपात को संकेत में सुधार करने के लिए नीतियों को लागू करने की कोशिश कर रहा है। कुछ लोग प्रश्न / उत्तर के दायरे के बारे में बहुत सख्त हैं, और कुछ समय के लिए अच्छा होना भूल जाते हैं (उदाहरण के लिए उनके अपमान पर टिप्पणी करके)
साइमन बर्गोट

@Simon धन्यवाद यह खराब संचार गुणवत्ता के कारण विघटित होता है जो इसे प्रदर्शित करता है। शायद वेब के गुमनाम घूंघट के पीछे "सख्त" होना थोड़ा आसान है? ओह अच्छी तरह से कुछ भी नया मुझे नहीं लगता। सकारात्मक प्रतिक्रिया के लिए फिर से धन्यवाद।
हाईवेलॉन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.