2009-12-13 22 views

उत्तर

68

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

दूसरी ओर, मॉड्यूल के बीच परिपत्र निर्भरता हानिकारक हैं। यह आमतौर पर एक खराब विचार-विमर्श मॉड्यूल संरचना, और/या मूल मॉड्यूलरेशन के साथ चिपकने में विफलता का संकेतक है। सामान्य रूप से, अनियंत्रित क्रॉस-निर्भरताओं वाले कोड-बेस को एक साफ, स्तरित मॉड्यूल संरचना के साथ एक से अधिक बनाए रखने के लिए कठिन और कठिन होना कठिन होगा। सभ्य मॉड्यूल के बिना, परिवर्तन के प्रभाव की भविष्यवाणी करना बहुत कठिन हो सकता है। और यह रखरखाव को कठिन बनाता है, और बीमार कल्पना वाले पैचिंग के परिणामस्वरूप "कोड क्षय" होता है।

(इसके अलावा, Maven जैसे उपकरणों परिपत्र निर्भरता के साथ संभाल नहीं होंगे मॉड्यूल (कलाकृतियों) का निर्माण।)

+6

शायद क्लासिक एसक्यूएल रिलेशनशिप टेबल का इस्तेमाल पालतू जानवर और मालिक के बीच निर्भरता की परिपत्र को दूर करने के लिए किया जा सकता है? किसी ऑब्जेक्ट में स्वामित्व टुपल्स को वापस करने के लिए मालिक/पालतू संबंधों और समर्थन सेट विधियों के संदर्भ में एक ऑब्जेक्ट (साथ ही साथ ऐसे रिश्तों को जोड़ने और निकालने के लिए)। उस योजना में पालतू और मालिक वर्ग प्रत्येक इस रिश्ते वर्ग पर निर्भर करते हैं। हालांकि, इसका उपयोग करने वाले वर्गों में से किसी एक पर निर्भर नहीं होना चाहिए। –

+7

@ जिम - मैं यह नहीं कह रहा हूं कि आप वर्गों के बीच परिपत्र निर्भरता को हटा नहीं सकते हैं। उदाहरण के लिए, आप 'मालिक' की बजाय 'ऑब्जेक्ट' वापस करने के लिए 'getOwner()' घोषित करके (कहें) कर सकते हैं। लेकिन, आईएमओ इस तरह की चीज के परिणामस्वरूप आपके द्वारा समाप्त किए गए परिपत्र निर्भरता की तुलना में खराब समस्याएं हो सकती हैं। –

7

क्योंकि अब वे वास्तव में एक ही वस्तु हैं। आप अलगाव में किसी एक का परीक्षण नहीं कर सकते हैं।

यदि आप एक को संशोधित करते हैं, तो संभव है कि आप इसके साथी को भी प्रभावित करें।

+0

क्या होगा यदि वे एक ही इंटरफ़ेस को लागू करते हैं? – Pierreten

+0

@Pierreten: फिर भी, यह एक ही कारण के लिए एक बुरा विचार है। – RCIX

+3

@RCIX - सावधान रहें। आपने ग्राफ, कुछ पेड़ और दोगुनी-लिंक्ड सूचियों से इंकार कर दिया है। – Kobi

6
विकिपीडिया से

:

सर्कुलर निर्भरता सॉफ्टवेयर प्रोग्राम में कई अवांछित प्रभाव पैदा कर सकता है। सॉफ़्टवेयर से सबसे समस्याग्रस्त डिज़ाइन बिंदु दृश्य तंग पारस्परिक रूप से निर्भर मॉड्यूल का युग्मन है जो को कम करता है या एकल मॉड्यूल के अलग-अलग पुन: उपयोग को असंभव बनाता है।

सर्कुलर निर्भरता (, कार्यक्रम त्रुटियों त्रुटियों संकलन) जब एक मॉड्यूल में एक छोटे स्थानीय परिवर्तन अन्य मॉड्यूल में फैलता है और अवांछित वैश्विक असर पड़ता है एक डोमिनो प्रभाव हो सकता है। परिपत्र निर्भरता भी असीमित रिकर्सन या अन्य अप्रत्याशित विफलताओं के परिणामस्वरूप हो सकती है।

सर्कुलर निर्भरता भी अप्रयुक्त वस्तुओं deallocating से कुछ बहुत आदिम स्वत: कचरा कलेक्टरों (उन है कि का उपयोग संदर्भ बढ़ रहा है) रोकने के द्वारा मेमोरी लीक हो सकती है।

+1

यह ऑब्जेक्ट संदर्भों की तुलना में असेंबली संदर्भों के बारे में अधिक है। –

+2

कितनी शानदार 'मेटा'। इस SO पृष्ठ में विकिपीडिया के साथ एक परिपत्र संदर्भ है। यह उत्तर विकिपीडिया का उद्धरण देता है, और विकिपीडिया पेज यहां वापस लिंक करता है: https://en.wikipedia.org/wiki/Circular_dependency (उस विकी पेज पर "बाहरी लिंक" देखें) – pestophagous

2

यह कोड पठनीयता को नुकसान पहुंचाता है। और परिपत्र निर्भरताओं से स्पेगेटी कोड तक केवल एक छोटा कदम है।

4

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

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

-2

.NET कचरा कलेक्टर परिपत्र संदर्भों को संभाल सकता है इसलिए .NET ढांचे पर काम करने वाले अनुप्रयोगों के लिए मेमोरी लीक का कोई डर नहीं है।

+1

"अनुप्रयोगों के लिए मेमोरी लीक का कोई डर नहीं है" I मुझे यकीन नहीं है कि क्या यह कथन बहुत सच है। – strager

+0

मैं strager से सहमत हूं; espcecially जब घटना हैंडलर को अलग करना भूल जाता है – Pierreten

+0

आवेदन स्कोप मेमोरी लीक .NET में संभव है; हालांकि, यहां वर्णित प्रकार * को जीसी द्वारा संभाला जाना चाहिए, जैसा कि कहा गया है, इवेंट हैंडलर एक अलग कहानी हैं। – Nate

1

यहाँ उदाहरण देकर स्पष्ट करना क्यों परिपत्र निर्भरता बुरा कर रहे हैं मदद मिल सकती है उदाहरण के एक जोड़े हैं।

समस्या # 1: पहले आरंभ/निर्माण क्या होता है?

class A 
{ 
    public A() 
    { 
    myB.DoSomething(); 
    } 

    private B myB = new B(); 
} 

class B 
{ 
    public B() 
    { 
    myA.DoSomething(); 
    } 

    private A myA = new A(); 
} 

कौन सा निर्माता पहले कहा जाता है:

निम्नलिखित उदाहरण पर विचार? सुनिश्चित करने के लिए वास्तव में कोई रास्ता नहीं है क्योंकि यह पूरी तरह संदिग्ध है। एक या अन्य कुछ तरीकों को किसी ऑब्जेक्ट पर बुलाया जा रहा है जो अनियमित है। जिसके परिणामस्वरूप गलत व्यवहार होता है और संभवत: अपवाद उठाया जा सकता है। इस समस्या के आसपास के तरीके हैं, लेकिन वे सभी बदसूरत हैं और उन्हें सभी गैर-कन्स्ट्रक्टर प्रारंभकर्ताओं की आवश्यकता होती है।

समस्या # 2:

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

class B; 

class A 
{ 
public: 
    A() : Refs(1) 
    { 
    myB = new B(this); 
    }; 

    ~A() 
    { 
    myB->Release(); 
    } 

    int AddRef() 
    { 
    return ++Refs; 
    } 

    int Release() 
    { 
    --Refs; 
    if(Refs == 0) 
     delete(this); 
    return Refs; 
    } 

    B *myB; 
    int Refs; 
}; 

class B 
{ 
public: 
    B(A *a) : Refs(1) 
    { 
    myA = a; 
    a->AddRef(); 
    } 

    ~B() 
    { 
    myB->Release(); 
    } 

    int AddRef() 
    { 
    return ++Refs; 
    } 

    int Release() 
    { 
    --Refs; 
    if(Refs == 0) 
     delete(this); 
    return Refs; 
    } 

    A *myA; 
    int Refs; 
}; 

// Somewhere else in the code... 
... 
A *localA = new A(); 
... 
localA->Release(); // OK, we're done with it 
... 

पहली नज़र में, कोई सोच सकता है कि यह कोड सही है। संदर्भ गिनती कोड बहुत सरल और सीधा है। हालांकि, इस कोड के परिणामस्वरूप स्मृति रिसाव होता है। जब ए का निर्माण होता है, तो शुरुआत में इसकी "1" की संदर्भ गणना होती है। हालांकि, encapsulated myB चर संदर्भ संख्या को बढ़ाता है, जिससे इसे "2" की गिनती मिलती है। जब स्थानीय ए जारी किया जाता है, तो गिनती घट जाती है, लेकिन केवल "1" पर वापस आती है। इसलिए, ऑब्जेक्ट लटका दिया गया है और कभी नहीं हटाया गया है।

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

+2

.NET का कचरा संग्रह एक मार्क-एंड-स्वीप एल्गोरिदम का उपयोग करता है जो सभी ज्ञात जड़ों (स्थिर सदस्यों, आदि) से शुरू होता है और वहां से प्रत्येक संदर्भ को चिह्नित करता है। कोई भी संदर्भ जो पहुंच योग्य नहीं है (चाहे वे एक दूसरे को संदर्भित करते हैं या नहीं) चिह्नित नहीं हैं, और इसलिए संग्रह के लिए योग्य बन जाते हैं। सर्कुलर संदर्भों के लिए आपको समस्याग्रस्त क्यों लगता है? –

+0

क्या आप ऑब्जेक्ट संदर्भ को शून्य के रूप में निर्दिष्ट नहीं कर सकते हैं जब आपको इसकी आवश्यकता नहीं है? –

56

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

  1. डेटा और ग्राफ स्थिरता। परिपत्र संदर्भों के साथ वस्तुओं को अद्यतन करने से यह सुनिश्चित करने में चुनौतियां पैदा हो सकती हैं कि समय के सभी बिंदुओं पर वस्तुओं के बीच संबंध वैध हैं। इस प्रकार की समस्या अक्सर ऑब्जेक्ट-रिलेशनल मॉडलिंग कार्यान्वयन में उत्पन्न होती है, जहां इकाइयों के बीच बिडरेक्शनल, सर्कुलर संदर्भ खोजने के लिए असामान्य नहीं है।

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

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

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

    class A 
    { 
        private readonly B m_B; 
        public A(B other) { m_B = other; } 
    } 
    
    class B 
    { 
        private readonly A m_A; 
        public A() { m_A = new A(this); } 
    } 
    
  5. कार्यक्रम readibility और रख-रखाव। परिपत्र संदर्भ स्वाभाविक रूप से नाजुक और तोड़ने में आसान हैं। यह आंशिक रूप से इस तथ्य से उपजी है कि कोड पढ़ने और समझने वाले परिपत्र संदर्भों में कोड से कठिन है जो उन्हें टालता है। यह सुनिश्चित करना कि आपका कोड समझने और बनाए रखने में आसान है, बग से बचने में मदद करता है और परिवर्तनों को अधिक आसानी से और सुरक्षित रूप से करने की अनुमति देता है। सर्कुलर संदर्भ वाले ऑब्जेक्ट यूनिट परीक्षण के लिए अधिक कठिन हैं क्योंकि उन्हें एक दूसरे से अलगाव में परीक्षण नहीं किया जा सकता है।

  6. ऑब्जेक्ट आजीवन प्रबंधन। जबकि .NET का कचरा कलेक्टर परिपत्र संदर्भों (और ऐसी वस्तुओं को सही तरीके से निपटाने) के साथ पहचानने और निपटने में सक्षम है, सभी भाषाओं/वातावरण नहीं कर सकते हैं। उन वातावरणों में जो उनके कचरा संग्रहण योजना (जैसे वीबी 6, ऑब्जेक्टिव-सी, कुछ सी ++ पुस्तकालयों) के लिए संदर्भ गिनती का उपयोग करते हैं, मेमोरी लीक में परिणामस्वरूप सर्कुलर संदर्भों के लिए यह संभव है। चूंकि प्रत्येक ऑब्जेक्ट दूसरे पर निर्भर करता है, इसलिए उनकी संदर्भ संख्या शून्य तक कभी नहीं पहुंच जाएगी, और इसलिए संग्रह और सफाई के लिए उम्मीदवार कभी नहीं बनेंगे।

1

सर्कुलर संदर्भों के साथ वस्तुओं को रखना सामान्य बात है। बिडरेक्शनल एसोसिएशन के साथ एक डोमेन मॉडल में। उचित रूप से लिखित डेटा एक्सेस घटक वाला एक ओआरएम इसे संभाल सकता है।

1

सी ++ सॉफ़्टवेयर डिज़ाइन में, लक्ष्को की पुस्तक का संदर्भ लें, चक्रीय भौतिक निर्भरता अवांछनीय है।कई कारण हैं:

  • इससे उन्हें स्वतंत्र रूप से पुन: उपयोग करने के लिए परीक्षण करना और असंभव बनाना मुश्किल हो जाता है।
  • इससे लोगों को समझने और बनाए रखने में मुश्किल होती है।
  • यह लिंक-टाइम लागत में वृद्धि करेगा।
1

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

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