मैं अपने गेम आर्किटेक्चर में कई सिंगललेट होने से कैसे बच सकता हूं?


55

मैं गेम बनाने के लिए cocos2d-x गेम इंजन का उपयोग करता हूं। इंजन पहले से ही कई सिंगलेट्स का उपयोग करता है। यदि कोई इसका उपयोग करता है, तो उन्हें उनमें से कुछ से परिचित होना चाहिए:

Director
SimpleAudioEngine
SpriteFrameCache
TextureCache
EventDispatcher (was)
ArmatureDataManager
FileUtils
UserDefault

और कुल मिलाकर लगभग 16 वर्गों के साथ। आप इस पेज पर एक समान सूची पा सकते हैं: Cocos2d-html5 v3.0 में सिंगलटन ऑब्जेक्ट्स लेकिन जब मैं लिखना चाहता हूं तो मुझे लगता है कि मुझे बहुत अधिक सिंग्लेटल्स की आवश्यकता है:

PlayerData (score, lives, ...)
PlayerProgress (passed levels, stars)
LevelData (parameters per levels and level packs)
SocialConnection (Facebook and Twitter login, share, friend list, ...)
GameData (you may obtain some data from server to configure the game)
IAP (for in purchases)
Ads (for showing ads)
Analytics (for collecting some analytics)
EntityComponentSystemManager (mananges entity creation and manipulation)
Box2dManager (manages the physics world)
.....

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

 - bad testability
 - no inheritance available
 - no lifetime control
 - no explicit dependency chain
 - global access (the same as global variables, actually)
 - ....

आप यहाँ कुछ विचार पा सकते हैं: https://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons और https://stackoverflow.com/questions/4074154/when-should-the-singleton -pattern-नहीं होने वाली इस्तेमाल किया-अलावा-स्पष्ट

इसलिए, मुझे लगता है, मैं कुछ गलत कर रहा हूं। मुझे लगता है कि मेरे कोड से बदबू आ रही है । :) मैं घायल कैसे अधिक अनुभवी खेल डेवलपर्स इस वास्तु समस्या का समाधान? मैं जांचना चाहता हूं, शायद 30 से अधिक सिंग्लेटों के लिए खेल के विकास में अभी भी सामान्य है , पहले से ही खेल इंजन में माना जाता है।

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


26
सिंगलटन के खिलाफ बहस करने वाले अधिकांश लोगों को यह महसूस नहीं होता है कि सभी कोड के माध्यम से कुछ डेटा / कार्यक्षमता को प्रचारित करने के लिए आवश्यक कार्य एक सिंगलटन का उपयोग करने की तुलना में अधिक बग स्रोत हो सकता है। इसलिए मूल रूप से वे तुलना नहीं कर रहे हैं, बस खारिज कर रहे हैं ==> मुझे एक आसन होने के लिए विरोधी-एकलौतीवाद पर संदेह है :-) इतनी अच्छी तरह से, सिंगलटन में खामियां हैं, इसलिए यदि आप इसे टाल सकते हैं, तो ऐसा करें ताकि आप उन मुद्दों से बचें जो इसके साथ आते हैं , अब यदि आप नहीं कर सकते, तो बिना पीछे देखे इसके लिए जाएं। आखिरकार, Cocos2d अपने 16 सिंग्लेटन्स के साथ काफी ठीक काम कर रहा है ...
GameAlchemist

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

मुझे लगता है कि ये एकल तब विश्व स्तर पर सुलभ हैं? जो उस पैटर्न से बचने का एक कारण होगा।
पीटर - मोनिका

जवाबों:


41

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

एक, आरंभ और सफाई का क्रम सरल और स्पष्ट है। गलती से एक सेवा शुरू करने का कोई तरीका नहीं है जैसे आप एक सिंगलटन के साथ कर सकते हैं।

दो, यह स्पष्ट है कि कौन किस पर निर्भर करता है। मैं आसानी से देख सकता हूं कि कक्षा घोषणा से सिर्फ किन सेवाओं की जरूरत है।

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


34
+1। इसके अलावा, सिस्टम के संदर्भों को पास करने की "झुंझलाहट" निर्भरता रेंगने का मुकाबला करने में मदद करती है; अगर आपको " सब कुछ " पास करना है , तो यह एक अच्छा संकेत है कि आपको अपने डिजाइन में एक खराब युग्मन समस्या है, और यह इस तरह से स्पष्ट है कि हर जगह से हर चीज के लिए वैश्विक पहुंच के साथ।
जोश

2
यह वास्तव में एक समाधान प्रदान नहीं करता है ... तो आप अपने प्रोग्राम क्लास को सिंगलटन ऑब्जेक्ट्स के एक समूह के साथ रखते हैं और अब दृश्य में कोडिंग में कोडिंग में 10 स्तर गहरे उन सिंग्लेटों में से एक की जरूरत है ... यह कैसे पारित किया जाता है?
वॉर

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

3
वे सिंगल नहीं हैं। वे एक अच्छी तरह से परिभाषित मालिक के साथ किसी भी चीज़ की तरह नियमित वस्तुएं हैं जो init / cleanup को नियंत्रित करती हैं। यदि आप बिना किसी पहुंच के साथ 10 स्तर गहरे हैं, तो शायद आपके पास एक डिज़ाइन समस्या है। सब कुछ की जरूरत नहीं है या रेंडरर्स, ऑडियो और इस तरह की पहुंच होनी चाहिए। इस तरह से आप अपने डिजाइन के बारे में सोचते हैं। उन लोगों के लिए एक अतिरिक्त बोनस के रूप में जो अपने कोड का परीक्षण करते हैं (क्या ??), यूनिट परीक्षण भी बहुत आसान हो जाता है।
मेगाडान

2
हां, मुझे लगता है कि निर्भरता इंजेक्शन (वसंत की तरह या इसके बिना) इस से निपटने के लिए एक सही समाधान है। मैंने पाया कि यह उन लोगों के लिए एक बढ़िया लेख है, जो यह सोच रहे हैं कि हर जगह से गुजरने वाली चीजों से बचने के लिए बेहतर संरचना कोड कैसे हो: misko.hevery.com/2008/10/21/…
megadan

17

मैं सिंगल के पीछे की बुराई के बारे में चर्चा नहीं करूंगा क्योंकि इंटरनेट मुझसे बेहतर कर सकता है।

अपने खेल में मैं सिंगलेट्स / मैनेजर्स के टन से बचने के लिए सर्विस लोकेटर पैटर्न का उपयोग करता हूं ।

अवधारणा बहुत सरल है। आपके पास केवल एक सिंगलटन है, जो सिंगलटन की तरह उपयोग करने के लिए उपयोग किए जाने वाले एकमात्र इंटरफ़ेस की तरह काम करता है। कई सिंगलटन होने के बजाय अब आपके पास केवल एक है।

कॉल जैसे:

FlyingToasterManager.GetInstance().Toast();
SmokeAlarmManager.GetInstance().Start();

सेवा लोकेटर पैटर्न का उपयोग करके ऐसा दिखता है:

SvcLocator.FlyingToaster.Toast();
SvcLocator.SmokeAlarm.Start();

जैसा कि आप देख सकते हैं कि हर सिंग्लटन सर्विस लोकेटर में निहित है।

अधिक विस्तृत व्याख्या करने के लिए मैं आपको लोकेटर पैटर्न का उपयोग करने के बारे में इस पृष्ठ को पढ़ने का सुझाव देता हूं ।

[ EDIT ]: जैसा कि टिप्पणियों में बताया गया है, साइट gameprogrammingpatterns.com में भी सिंगलटन पर एक बहुत ही दिलचस्प खंड है

मुझे उम्मीद है यह मदद करेगा।


4
यहाँ से जुड़ी साइट, gameprogrammingpatterns.com पर भी प्रासंगिकता महसूस करने वाले सिंग्लेटन्स पर एक अध्याय है
ajp15243

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

2
क्या आप "उचित निर्भरता इंजेक्शन" पर विस्तार से बता सकते हैं?
ब्लू विजार्ड

17
यह वास्तव में इस मुद्दे की मदद नहीं करता है। यह अनिवार्य रूप से बहुत सारे सिंगलटन एक विशालकाय सिंगलटन में विलीन हो गए हैं। अंतर्निहित संरचनात्मक मुद्दों में से कोई भी तय नहीं है या यहां तक ​​कि संबोधित किया गया है, कोड अभी भी अपनी बस अब पहले से ही बदबू आ रही है।
क्लासिकथंडर

4
@classicthunder जबकि यह हर एक मुद्दे को संबोधित नहीं करता है, यह सिंग्लेटन्स पर एक बड़ा सुधार है क्योंकि यह कई पते करता है। विशेष रूप से, आपके द्वारा लिखा गया कोड अब किसी एकल वर्ग के लिए युग्मित नहीं है, बल्कि एक इंटरफ़ेस / वर्गों की श्रेणी है। अब आप आसानी से विभिन्न सेवाओं के विभिन्न कार्यान्वयन को स्वैप कर सकते हैं।
झॉकिंग

12

इन सभी उत्तरों, टिप्पणियों और लेखों को पढ़ना, विशेष रूप से इन दो शानदार लेखों को पढ़ना,

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

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

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

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

EDIT: एक साल के काम के बाद और प्रत्यक्ष DI का उपयोग करने और विशाल कंस्ट्रक्टर और बहुत सारे प्रतिनिधिमंडल के साथ समस्याएँ होने के बाद, मैंने अधिक शोध किया है और एक अच्छा लेख पाया है जो DI और सेवा लोकेटर विधियों के बारे में पेशेवरों और विपक्षों के बारे में बात करता है। मार्टिन फॉवलर द्वारा इस लेख ( http://www.martinfowler.com/articles/injection.html ) का हवाला देते हुए बताया गया है कि जब वास्तव में सर्विस लोकेटर खराब होते हैं:

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

लेकिन वैसे भी, अगर आप हमें पहली बार DI चाहते हैं, तो आपको इस http://misko.hevery.com/2008/10/21/d dependency-injection-myth-reference-passing/ लेख (@megadan द्वारा इंगित) को पढ़ना चाहिए , कानून के कानून (LoD) या कम से कम ज्ञान के सिद्धांत पर बहुत सावधान ध्यान देकर ।


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

3

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

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

इसलिए खुद से पूछिए कि कौन सी चीज को बनाए रखना आसान है।

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

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

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


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

1

सिंगलटन एक प्रसिद्ध पैटर्न है, लेकिन यह उन उद्देश्यों को जानना अच्छा है जो यह कार्य करता है, और इसके पेशेवरों और विपक्ष।

यह वास्तव में समझ में आता है अगर कोई संबंध नहीं है
यदि आप अपने घटक को पूरी तरह से अलग वस्तु (कोई मजबूत निर्भरता) के साथ नहीं संभाल सकते हैं और एक ही व्यवहार होने की उम्मीद करते हैं, तो सिंगलटन एक अच्छा विकल्प हो सकता है।

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

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

आपको एक कंपोनेंट को एक कंपोनेंट की बजाय एक सर्विस की तरह देखना होगा ।

सिंग्लेटन्स काम करते हैं, उन्होंने कभी कोई आवेदन नहीं तोड़ा। लेकिन उनकी कमी (आपके द्वारा दिए गए चार) कारण हैं जो आप एक नहीं करेंगे।


1

इंजन पहले से ही कई सिंगलेट्स का उपयोग करता है। यदि कोई इसका उपयोग करता है, तो उन्हें उनमें से कुछ से परिचित होना चाहिए:

अपरिचितता ही वह कारण नहीं है जिसके कारण सिंगलटन से बचने की आवश्यकता है।

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

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

वे अच्छे कारण हैं कि ये सेवाएं एकल क्यों हैं। हालाँकि, एकल कारणों में से कोई भी आपके द्वारा सूचीबद्ध कक्षाओं पर लागू नहीं होता है।

क्योंकि मुझे अपने खेल में बहुत अलग स्थानों पर उनकी आवश्यकता होगी, और साझा पहुंच बहुत आसान होगी।

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

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

चलो अपनी कक्षाओं को बिट द्वारा देखें:


PlayerData (score, lives, ...)
LevelData (parameters per levels and level packs)
GameData (you may obtain some data from server to configure the game)

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


IAP (for in purchases)
Ads (for showing ads)

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


EntityComponentSystemManager (mananges entity creation and manipulation)

दूसरे शब्दों में, एक निर्माणकर्ता और एक सेवा परत? यह वर्ग स्पष्ट सीमाओं के साथ क्यों नहीं है और न ही इसका उद्देश्य पहले स्थान पर है?


PlayerProgress (passed levels, stars)

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


Box2dManager (manages the physics world)

मैं वास्तव में इस पर आगे कोई टिप्पणी नहीं कर सकता, बिना यह जाने कि यह वर्ग वास्तव में क्या करता है, लेकिन एक बात स्पष्ट है कि इस वर्ग का नाम खराब है।


Analytics (for collecting some analytics)
SocialConnection (Facebook and Twitter login, share, friend list, ...)

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

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


-1

मेरे लिए सिंगलटन हमेशा बुरे होते हैं।

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

वैश्विक दायरे में कुछ कहने से आप मूल रूप से कह रहे हैं "यह हेटिंग ईश्वर है और इसका कोई मास्टर नहीं है" जो उदाहरण आप ऊपर प्रदान करते हैं, मैं कहूंगा कि इनमें से अधिकांश सहायक वर्ग या GameServices हैं, जिस स्थिति में खेल उनके लिए जिम्मेदार होगा।

लेकिन यह सिर्फ मेरे इंजन में मेरा डिजाइन है, आपकी स्थिति अलग हो सकती है।

इसे और अधिक सीधे रूप से कहना ... एकमात्र वास्तविक सिंगलटन खेल है क्योंकि यह कोड के हर हिस्से का मालिक है।

यह उत्तर प्रश्न की व्यक्तिपरक प्रकृति पर आधारित है और पूरी तरह से मेरी राय पर आधारित है, यह सभी डेवलपर्स के लिए सही नहीं हो सकता है।

संपादित करें: अनुरोध के रूप में ...

ठीक है, यह मेरे सिर से है क्योंकि मेरे पास इस समय मेरे सामने मेरा कोड नहीं है, लेकिन अनिवार्य रूप से किसी भी गेम की जड़ में गेम क्लास है जो वास्तव में एक सिंगलटन है ... यह होना है!

इसलिए मैंने निम्नलिखित जोड़ा ...

class Game
{
   IList<GameService> Services;

   public T GetService<T>() where T : GameService
   {
       return Services.FirstOrDefatult(s => s is T);
   }
}

अब मेरे पास एक सिस्टम क्लास (स्थिर) भी है जिसमें पूरे कार्यक्रम से मेरे सभी सिंगलेट्स शामिल हैं (इसके बारे में बहुत कम, गेम और कॉन्फिग ऑप्शन और इसके बारे में) ...

public static class Sys
{
    // only the main game assembly can set this (done by the game ctor)
    // anything can get
    public static Game Game { get; internal set; }
}

और उपयोग ...

कहीं से भी मैं कुछ ऐसा कर सकता हूं

var tService = Sys.Game.getService<T>();
tService.Something();

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

मेरे पास ऐसी सेवाएं भी हैं जो अधिक विशिष्ट दृश्य परिदृश्यों के लिए अन्य सेवाएँ इनहेरिट / विस्तारित करती हैं।

उदाहरण के लिए ...

मेरे पास एक भौतिकी सेवा है जो मेरी भौतिकी सिमुलेशन को संभालती है, लेकिन दृश्य भौतिकी के आधार पर कुछ अलग व्यवहार की आवश्यकता हो सकती है।


1
क्या खेल सेवाओं को केवल एक बार ही चालू नहीं किया जाना चाहिए? यदि ऐसा है, तो यह सिर्फ एक सिंगलटन पैटर्न है जिसे कक्षा स्तर पर लागू नहीं किया गया है, जो कि एक ठीक से लागू किए गए सिंगलटन की तुलना में सबसे खराब है।
GameAlchemist

2
@Wardy मुझे स्पष्ट रूप से समझ में नहीं आया है कि आपने क्या किया है, लेकिन ऐसा लगता है कि मैंने जिस सिंग्लटन-फैकेड का वर्णन किया है और यह एक GOD ऑब्जेक्ट बनना चाहिए, है ना?
नारेक

10
यह सिर्फ एक सिंगलटन पैटर्न है जिसे खेल के स्तर पर लागू किया गया है। तो मूल रूप से इसका सबसे दिलचस्प पहलू यह है कि आप यह दिखावा करने की अनुमति दें कि आप सिंगलटन का उपयोग नहीं कर रहे हैं। उपयोगी है अगर आपका बॉस एंटी-पैटर्न चर्च से है।
GameAlchemist 12

2
मुझे यकीन नहीं है कि यह सिंगलेट्स का उपयोग करने से कैसे प्रभावी रूप से अलग है। केवल इस बात में अंतर नहीं है कि आप इस प्रकार की अपनी एकल मौजूदा सेवा का उपयोग कैसे करते हैं? यानी स्किप var tService = Sys.Game.getService<T>(); tService.Something();करने के बजायgetServiceभाग और सीधे उस तक पहुंचने के ?
ईसाई

1
@ क्रिसियन: वास्तव में, यह वही है जो सेवा लोकेटर एंटीपैटर्न है। जाहिर है कि यह समुदाय अभी भी सोचता है कि यह एक अनुशंसित डिजाइन पैटर्न है।
मैजस

-1

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

तुलना करें, उदाहरण के लिए, जावा की HashMap .NET के साथDictionary । दोनों काफी समान हैं, लेकिन उनके पास एक महत्वपूर्ण अंतर है: जावा का HashMapउपयोग करने के लिए कठिन-कोडित है equalsऔर hashCode(यह प्रभावी रूप से एक सिंगलटन तुलनित्र का उपयोग करता है) जबकि .NET एक निर्माता पैरामीटर Dictionaryके IEqualityComparer<T>रूप में एक उदाहरण स्वीकार कर सकता है । रन-टाइम की लागत IEqualityComparerकम से कम है, लेकिन यह जिस जटिलता का परिचय देता है वह नहीं है।

क्योंकि प्रत्येक Dictionaryउदाहरण एक अतिक्रमण करता है IEqualityComparer, इसकी स्थिति वास्तव में इसमें निहित कुंजियों और उनके संबद्ध मूल्यों के बीच मानचित्रण नहीं है, बल्कि इसके बजाय कुंजियों और तुलनित्र और उनके संबंधित मूल्यों द्वारा परिभाषित समतुल्य सेटों के बीच एक मानचित्रण है । यदि दो उदाहरणों d1और d2कीDictionary एक ही करने के लिए पकड़ संदर्भ IEqualityComparerमें, यह एक नया उदाहरण उत्पादन करने के लिए संभव हो जाएगा d3ऐसी है कि किसी के लिए x, d3.ContainsKey(x)के बराबर होगा d1.ContainsKey(x) || d2.ContainsKey(x)। यदि, हालांकि, d1और d2अलग-अलग मनमानी समानता तुलनाओं के संदर्भ रख सकते हैं, तो सामान्य रूप से उन्हें विलय करने का कोई तरीका नहीं होगा ताकि यह सुनिश्चित किया जा सके कि शर्त रखी जाए।

एकल को समाप्त करने के प्रयास में उदाहरण चर जोड़ते हुए, लेकिन उन नए उदाहरणों के लिए संभव नए राज्यों के लिए ठीक से खाते में असफल रहना, जो चर चर द्वारा कोड बनाए जा सकते हैं, जो एकल की तुलना में अधिक भंगुर होने के कारण समाप्त होता है। यदि प्रत्येक ऑब्जेक्ट इंस्टेंस में एक अलग फ़ील्ड है, लेकिन चीजें बुरी तरह से खराब हो जाएंगी जब तक कि वे सभी एक ही ऑब्जेक्ट इंस्टेंस की पहचान नहीं करते हैं, तो सभी नए फ़ील्ड्स ने खरीद लिया है तरीकों की एक बढ़ी हुई संख्या है जो चीजें गलत हो सकती हैं।


1
हालांकि यह निश्चित रूप से चर्चा का एक दिलचस्प पहलू है, मुझे नहीं लगता कि यह वास्तव में ओपी द्वारा पूछे गए प्रश्न को संबोधित करता है।
जोश

1
@JoshPetrie: मूल पोस्ट (जैसे मैगस) पर टिप्पणियों ने सुझाव दिया कि एकल का उपयोग करने से बचने के लिए संदर्भों को ले जाने की रनटाइम लागत बहुत अच्छी नहीं थी। इस तरह के रूप में, मैं प्रासंगिक विचार करेगा अर्थ हर वस्तु एकमात्र बचने के प्रयोजन के लिए संदर्भ संपुटित होने की लागत। एकल मामलों में एकल से बचना चाहिए जहां उन्हें सस्ते और आसानी से टाला जा सकता है, लेकिन कोड जिसे किसी सिंगलटन की आवश्यकता नहीं होती है, लेकिन जैसे ही मौजूद कुछ चीज़ों के कई उदाहरण टूट सकते हैं कोड से भी बदतर है जो सिंगलटन का उपयोग करता है।
सुपरकाट

2
उत्तर उन टिप्पणियों को संबोधित करने के लिए नहीं हैं जो वे सीधे सवाल का जवाब देने के लिए हैं।
क्लासिकथंडर

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