परिपत्र वर्ग की निर्भरता


12

क्या 2 वर्गों के लिए बुरा डिज़ाइन है, जिन्हें एक दूसरे की ज़रूरत है?

मैं एक छोटा खेल लिख रहा हूं जिसमें मेरे पास एक GameEngineवर्ग है जिसे कुछ GameStateवस्तुएं मिली हैं। कई प्रतिपादन विधियों का उपयोग करने के लिए, इन GameStateवस्तुओं को भी GameEngineवर्ग को जानना आवश्यक है - इसलिए यह एक परिपत्र निर्भरता है।

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


2
मुझे बहुत आश्चर्य होगा अगर जवाब हाँ था।
doppelgreener

चूँकि दो प्रश्न हैं, जो तार्किक रूप से असंगत हैं .. इसका उत्तर उनमें से एक है। आप ऐसा राज्य क्यों डिज़ाइन करना चाहते हैं जो वास्तव में कुछ करता है? राज्य की जाँच करने और कार्रवाई करने के लिए आपके पास एक प्रबंधक / नियंत्रक होना चाहिए .. यह किसी अन्य प्रकार की ज़िम्मेदारियों को संभालने के लिए एक प्रकार का भ्रम है। यदि आप इसे करना चाहते हैं, तो C ++ आपका मित्र है
तियोड्रोन

मेरी गेमस्टेट कक्षाएं इंट्रो, वास्तविक गेम, एक मेनू और इसी तरह की चीजें हैं। GameEngine एक स्टैक में इन राज्यों को संग्रहीत करता है, इसलिए मैं एक राज्य को थामने और एक मेनू खोलने, या एक cutscene खेलने में सक्षम हूं, ... GameState वर्गों को GameEngine को जानने की आवश्यकता है, क्योंकि इंजन विंडो बनाता है और इसमें रेंडर का विवरण होता है ।
shad0w

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

जवाबों:


0

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

अब आपके मामले में, GameEnigne और GameState के लिए दो अलग-अलग वर्गों का होना बेहतर है। चूँकि मूल रूप से वे दोनों अलग-अलग काम कर रहे हैं, और बाद में आप बहुत सारी कक्षाओं को परिभाषित कर सकते हैं जो GameState को विरासत में देती हैं (जैसे आपके खेल में प्रत्येक दृश्य के लिए GameState)। और कोई भी एक दूसरे के लिए उपयोग करने की उनकी आवश्यकता से इनकार नहीं कर सकता है। मूल रूप से GameEngine gamestates चल रहा है, इसलिए यह उनके लिए एक संकेतक होना चाहिए। और GameState GameEngine (जैसे गाया, भौतिकी प्रबंधक, आदि) में परिभाषित संसाधनों का उपयोग कर रहे हैं।

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

अब तक हम जानते हैं कि हमें आउट डिज़ाइन में परिपत्र निर्भरता की आवश्यकता है। इसे सुरक्षित रूप से बनाने के कई तरीके हैं:

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

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


6

क्या 2 वर्गों के लिए बुरा डिज़ाइन है, जिन्हें एक दूसरे की ज़रूरत है?

यह एक कोड गंध का एक सा है , लेकिन एक इसके साथ छोड़ सकता है। यदि आपके गेम को चलाने और चलाने का सबसे आसान और तेज़ तरीका है, तो इसके लिए जाएं। लेकिन इसे ध्यान में रखें क्योंकि एक अच्छा मौका है कि आपको किसी बिंदु पर इसे फिर से भरना होगा।

C ++ के साथ बात यह है कि परिपत्र निर्भरता इतनी आसानी से संकलित नहीं होगी , इसलिए आपके संकलन को ठीक करने में समय बिताने के बजाय उनसे छुटकारा पाने के लिए एक बेहतर विचार हो सकता है।

कुछ और राय के लिए SO पर यह प्रश्न देखें ।

क्या आप [मेरे डिज़ाइन] को ख़राब डिज़ाइन कहेंगे?

नहीं, यह अभी भी एक कक्षा में सब कुछ डालने से बेहतर है।

यह बहुत अच्छा नहीं है, लेकिन यह वास्तव में मैंने देखा है सबसे कार्यान्वयन के लिए काफी करीब है। आमतौर पर, आपके पास गेम स्टेट्स के लिए एक प्रबंधक वर्ग होगा ( सावधान! ), और एक रेंडरर वर्ग, और यह काफी सामान्य है कि वे एकल हैं। तो परिपत्र निर्भरता "छिपी" है, लेकिन यह संभवतः वहां है।

साथ ही, जैसा कि आपको टिप्पणियों में बताया गया था, यह थोड़ा अजीब है कि खेल राज्य कक्षाएं किसी प्रकार का प्रतिपादन करती हैं। उन्हें बस राज्य की जानकारी रखनी चाहिए, और रेंडरिंग को एक रेंडरर या गेम ऑब्जेक्ट्स के कुछ ग्राफिक कंपोनेंट को खुद हैंडल करना चाहिए।

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


यह एक कोड गंध क्यों होगा? माता-पिता-बच्चे के संबंध वाली अधिकांश वस्तुओं को एक-दूसरे को देखने की जरूरत है।
ककईमारू

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

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

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

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

6

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

हालांकि, 2 वस्तुओं का एक-दूसरे के लिए संदर्भित करना बहुत आम है , और यहां अंतर यह है कि आमतौर पर एक दिशा में संबंध अधिक सार है। उदाहरण के लिए, एक मॉडल-व्यू-कंट्रोलर सिस्टम में, व्यू ऑब्जेक्ट मॉडल ऑब्जेक्ट के लिए एक संदर्भ रख सकता है, और इसके बारे में सभी को पता चल जाएगा, इसके सभी तरीकों और गुणों तक पहुंचने में सक्षम होने के नाते, ताकि व्यू प्रासंगिक डेटा के साथ खुद को पॉप्युलेट कर सके । मॉडल ऑब्जेक्ट दृश्य में वापस संदर्भ रख सकता है, ताकि यह तब अपडेट हो सके जब उसका अपना डेटा बदल गया हो। लेकिन मॉडल के बजाय एक संदर्भ देखें - जो मॉडल को दृश्य पर निर्भर करेगा - आमतौर पर दृश्य एक अवलोकन इंटरफ़ेस को लागू करता है, अक्सर सिर्फ 1 के साथ।Update()फ़ंक्शन, और मॉडल एक ऑब्जर्वेबल ऑब्जेक्ट का संदर्भ रखता है, जो एक दृश्य हो सकता है। जब मॉडल बदलता है, तो वह Update()अपने सभी ऑब्ज़र्वबल्स, और व्यू Update()को मॉडल में वापस बुलाकर और किसी भी अद्यतन जानकारी को प्राप्त करके लागू करता है। यहां लाभ यह है कि मॉडल को दृश्यों के बारे में कुछ भी पता नहीं है (और यह क्यों होना चाहिए?), और अन्य स्थितियों में फिर से उपयोग किए जा सकते हैं, यहां तक ​​कि बिना व्यू के भी।

आपके खेल में भी ऐसी ही स्थिति है। GameEngine आमतौर पर GameStates के बारे में जानता होगा। लेकिन GameState को GameEngine के बारे में सब कुछ जानने की ज़रूरत नहीं है - इसे GameEngine पर कुछ रेंडरिंग तरीकों तक पहुँच की आवश्यकता है। कि आपके सिर में थोड़ा अलार्म सेट करना चाहिए जो कहता है कि या तो (ए) गेमइंजीन एक वर्ग के भीतर बहुत सारे काम करने की कोशिश कर रहा है, और / या (बी) गेमस्टेट को पूरे गेम इंजन की आवश्यकता नहीं है, बस रेंडर करने योग्य भाग।

इसे हल करने के लिए तीन तरीकों में शामिल हैं:

  • GameEngine को एक Renderable इंटरफ़ेस से प्राप्त करें, और उस संदर्भ को GameState में पास करें। यदि आप कभी भी रेंडरिंग पार्ट को रिफलेक्टर करते हैं, तो आपको यह सुनिश्चित करना होगा कि यह समान इंटरफ़ेस रखता है।
  • फैक्टर रेंडरिंग भाग को एक नए रेंडरर ऑब्जेक्ट में बदल देता है, और इसके बजाय GameStates को पास करता है।
  • जैसा है वैसा ही छोड़ दो। हो सकता है कि किसी समय आप GameState से सभी GameEngine कार्यक्षमता का उपयोग करना चाहते हैं, सब के बाद। लेकिन इस बात को ध्यान में रखें कि सॉफ्टवेयर जो बनाए रखना आसान है और विस्तार करना आसान है, इसके लिए आमतौर पर प्रत्येक वर्ग को बाहर की तरफ जितना संभव हो उतना कम देखने की आवश्यकता होती है, यही वजह है कि चीजों को उप-ऑब्जेक्ट और इंटरफेस में तोड़ना जो एक और अच्छी तरह से प्रदर्शन करते हैं- परिभाषित कार्य बेहतर है।

0

यह आमतौर पर कम युग्मन के साथ उच्च सामंजस्य रखने के लिए अच्छा अभ्यास माना जाता है। यहाँ युग्मन और सामंजस्य के संबंध में कुछ लिंक दिए गए हैं।

विकिपीडिया युग्मन

विकिपीडिया सामंजस्य

कम युग्मन, उच्च सामंजस्य

सबसे अच्छा अभ्यास पर stackoverflow

दो वर्गों के संदर्भ में एक-दूसरे के उच्च युग्मन होने पर। गूगल guice ढांचे उद्देश्य निर्भरता इंजेक्शन के साधनों के माध्यम से कम युग्मन के साथ उच्च सामंजस्य प्राप्त करने के लिए। मैं आपको सुझाव दूंगा कि आप इस विषय पर थोड़ा और पढ़ें और फिर अपना कॉल अपने संदर्भ में दें।

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