एकल उत्तरदायित्व पैटर्न कक्षाओं के लिए कितना विशिष्ट होना चाहिए?


14

उदाहरण के लिए, मान लें कि आपके पास कंसोल गेम प्रोग्राम है, जिसमें कंसोल से और उसके पास सभी प्रकार के इनपुट / आउटपुट तरीके हैं। यह उन सब को एक एकल में रखने के लिए बुद्धिमानी होगी inputOutputवर्ग या जैसी अधिक विशिष्ट वर्गों के लिए उन्हें नीचे तोड़ने startMenuIO, inGameIO, playerIO, gameBoardIO, हर वर्ग के 1-5 तरीकों के बारे में है आदि ऐसी है कि?

और एक ही नोट पर, अगर उन्हें तोड़ना बेहतर है, तो क्या उन्हें IOनामस्थान में रखना बेहतर होगा, इस तरह उन्हें थोड़ा और क्रिया करना कहते हैं, जैसे: IO.inGameआदि?



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

1
वैसे भी आप किस भाषा में लोअर केमेलकैसेज़ में कक्षाएं लेते हैं?
user253751

जवाबों:


7

अद्यतन (पुनर्कथन)

जब से मैंने एक बल्कि मौखिक उत्तर लिखा है, यहाँ यह सब उबलता है:

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

मुझे लगता है कि आप इसे गलत तरीके से देख रहे हैं। आप अनुप्रयोग के घटकों के कार्य में IO को अलग कर रहे हैं, जबकि - मेरे लिए- यह स्रोत के आधार पर अलग IO वर्ग और IO के "प्रकार" के लिए अधिक समझ में आता है ।

कुछ बेस / जेनेरिक KeyboardIOक्लासेस के MouseIOसाथ शुरू करने के लिए, और उसके बाद आपको कब और कहाँ उनकी ज़रूरत है, इसके आधार पर, उपवर्ग होते हैं जो हैंडल को IO को अलग तरीके से कहते हैं।
उदाहरण के लिए, टेक्स्ट इनपुट एक ऐसी चीज है जिसे आप शायद अलग-अलग इन-गेम नियंत्रणों को संभालना चाहते हैं। आप प्रत्येक उपयोग के मामले के आधार पर खुद को कुछ खास तरह की नक्शों को देखना चाहते हैं, लेकिन यह मैपिंग आईओ का हिस्सा नहीं है, यह है कि आप आईओ को कैसे संभाल रहे हैं।

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

फिर मैं इन ऑब्जेक्ट्स को एक हैंडलर ऑब्जेक्ट में इंजेक्ट करूँगा जो या तो कच्चे IO को किसी चीज़ पर मैप करेगा, जो कि मेरे एप्लिकेशन लॉजिक के साथ काम कर सकता है (जैसे: यूजर प्रेस "w" , हैंडलर मैप्स उस पर MOVE_FORWARD)।

ये हैंडलर, बारी-बारी से पात्रों को स्थानांतरित करने के लिए उपयोग किए जाते हैं, और तदनुसार स्क्रीन को आकर्षित करते हैं। एक सकल निरीक्षण, लेकिन इसका सार इस तरह की संरचना है:

[ IO.Keyboard.InGame ] // generic, if SoC and SRP are strongly adhered to, changing this component should be fairly easy to do
   ||
   ==> [ Controls.Keyboard.InGameMapper ]

[ Game.Engine ] <- Controls.Keyboard.InGameMapper
                <- IO.Screen
                <- ... all sorts of stuff here
    InGameMapper.move() //returns MOVE_FORWARD or something
      ||
      ==> 1. Game.updateStuff();//do all the things you need to do to move the character in the given direction
          2. Game.Screen.SetState(GameState); //translate the game state (inverse handler)
          3. IO.Screen.draw();//generate actual output

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

हर एक वर्ग के पास एक ही काम होता है: कीबोर्ड इनपुट को संभालना एक ऐसे वर्ग द्वारा किया जाता है, जो यह नहीं जानता / परवाह करता है / यह जानना चाहता है कि यह इनपुट का क्या मतलब है। यह सब पता है कि इनपुट कैसे प्राप्त करें (बफर, असंबद्ध, ...)।

हैंडलर इस जानकारी का अर्थ बनाने के लिए आवेदन के बाकी हिस्सों के लिए एक आंतरिक प्रतिनिधित्व में अनुवाद करता है।

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

ये ऑब्जेक्ट्स अपने राज्य को वापस रिले करते हैं, और यह डेटा पास हो जाता है Game.Screen, जो कि एक उलटा आईओ हैंडलर है। यह आंतरिक IO.Screenआउटपुट को वास्तविक आउटपुट उत्पन्न करने के लिए उपयोग कर सकते हैं।


चूंकि यह एक कंसोल एप्लिकेशन है जिसमें कोई माउस नहीं है, और संदेश या बोर्ड को प्रिंट करना इनपुट के साथ कसकर जुड़ा हुआ है। आपके उदाहरण में, उपवर्गों के साथ नाम IOऔर gameनाम या वर्ग हैं?
शिंज़ौ

@ कुक्कू: वे नामस्थान हैं। जो मैं कह रहा हूं उसका सार यह है कि, यदि आप अपने द्वारा आवेदन के किस भाग के आधार पर उपवर्गों का निर्माण करना चुनते हैं, तो आप प्रभावी रूप से अपने आवेदन तर्क के साथ मूल IO कार्यक्षमता को कसकर युग्मित कर रहे हैं। आप आवेदन के कार्य में IO के लिए जिम्मेदार कक्षाओं के साथ समाप्त करेंगे । मेरे लिए, यह SRP के उल्लंघन जैसा लगता है।
नामांकित

मैंने अपना उत्तर अपडेट कर लिया है, अपने उत्तर को संक्षेप में प्रस्तुत करने के लिए
एलियास वान ओओटगेम

हाँ, यह वास्तव में एक और समस्या है जो (तर्क के साथ आईओ को युग्मित करना) है, इसलिए आप वास्तव में आउटपुट से इनपुट को अलग करने की सलाह देते हैं?
शिंज़ौ

@ कुक्कू: यह वास्तव में आप क्या कर रहे हैं पर निर्भर करता है, और इनपुट / आउटपुट सामान कितना जटिल है। यदि हैंडलर (ट्रांसलेटिंग गेम स्टेट बनाम रॉ इनपुट / आउटपुट) बहुत अधिक भिन्न होते हैं, तो आप शायद इनपुट और आउटपुट कक्षाओं को अलग करना चाहते हैं, यदि नहीं, तो एक एकल IO वर्ग ठीक है
एलियास वान ओओटगेम

23

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

एक सड़क वाहन, आमतौर पर चार पहियों के साथ, एक आंतरिक दहन इंजन द्वारा संचालित होता है।

फिर आप "वाहन", "सड़क", "पहिए" आदि चीजों को अलग से परिभाषित करेंगे। आप यह कहने की कोशिश नहीं करेंगे:

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

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


तो कई के बजाय कुछ शब्दों के साथ कार को परिभाषित करने के साथ, फिर छोटे विशिष्ट लेकिन समान वर्गों को परिभाषित करना ठीक है?
शिंज़ौ

2
@ कुक्कू: छोटा अच्छा है। विशिष्ट अच्छा है। जब तक आप इसे DRY रखते हैं, तब तक ठीक है। आप अपने डिजाइन को बदलने में आसान बनाने की कोशिश कर रहे हैं। चीजों को छोटा और विशिष्ट रखने से आपको यह पता चलता है कि बदलाव कहां करना है। इसे DRY में रखने से बहुत सी जगहों को बदलने से बचने में मदद मिलती है।
वॉन काटो

6
आपका दूसरा वाक्य "लानत है, शिक्षक ने कहा कि यह 4 पृष्ठों की जरूरत है ... 'मकसद शक्ति उत्पन्न करता है' यह है !!"
corsiKa

2

मैं कहूंगा कि जाने का सबसे अच्छा तरीका है कि उन्हें अलग-अलग कक्षाओं में रखा जाए। छोटी कक्षाएं खराब नहीं हैं, वास्तव में ज्यादातर समय वे एक अच्छा विचार हैं।

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


0

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

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

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