क्या हमें हर चीज के लिए प्रकार निर्धारित करना चाहिए?


141

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

अंतर की चिंताओं के कारण आईडी को एक यादृच्छिक स्ट्रिंग होना चाहिए था। इसने एक विधि बनाई जिसमें बहुत अस्पष्ट हस्ताक्षर थे जैसे:

public string CreateNewThing()

यह रिटर्न प्रकार का इरादा स्पष्ट नहीं करता है। मैंने इस स्ट्रिंग को एक अन्य प्रकार से लपेटने के लिए सोचा जो इस तरह से इसका अर्थ स्पष्ट करता है:

public OperationIdentifier CreateNewThing()

प्रकार में केवल स्ट्रिंग होगी और जब भी इस स्ट्रिंग का उपयोग किया जाएगा, तब उपयोग किया जाएगा।

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

क्या आपको लगता है कि सुरक्षा कारणों से एक वर्ग में सरल प्रकार लपेटना एक अच्छा अभ्यास है?


4
आपको टिनी टाइप के बारे में पढ़ने में दिलचस्पी हो सकती है। मैं इसके साथ थोड़ा खेलता था और इसकी सिफारिश नहीं करता था लेकिन यह सोचने के लिए एक मजेदार तरीका है। darrenhobbs.com/2007/04/11/tiny-types
Jeroen Vannevel

40
एक बार जब आप हास्केल की तरह कुछ का उपयोग करते हैं, तो आप देखेंगे कि प्रकारों का उपयोग करने से कितना मदद मिलती है। प्रकार एक सही कार्यक्रम सुनिश्चित करने में मदद करते हैं।
नैट सीमर

3
यहां तक ​​कि Erlang जैसी एक गतिशील भाषा एक प्रकार की प्रणाली से लाभान्वित होती है, यही वजह है कि इसमें डायनेमिक भाषा होने के बावजूद Haskellers से परिचित एक टाइपस्पेक सिस्टम और टाइपकास्टिंग टूल है। C / C ++ जैसी भाषाएँ जहाँ कुछ भी वास्तविक प्रकार का एक पूर्णांक होता है जिसे हम संकलक के साथ एक निश्चित तरीके से व्यवहार करने के लिए सहमत होते हैं, या जावा जहाँ आप लगभग सॉर्ट करते हैं यदि आप कक्षाओं का नाटक करने का निर्णय लेते हैं तो वे एक प्रकार से या तो सिमेंटिक ओवरलोडिंग समस्या है। भाषा (क्या यह "वर्ग" या "प्रकार" है?) या प्रकार की अस्पष्टता (क्या यह "URL", "स्ट्रिंग" या "UPC" है?)। अंत में, जो भी उपकरण आप कर सकते हैं उसका उपयोग करें।
zxq9

7
मुझे यकीन नहीं है कि यह विचार कहां से आता है कि C ++ में प्रकारों पर एक ओवरहेड है। C ++ 11 के साथ, संकलक निर्माताओं में से किसी ने भी प्रत्येक लैंबडा को अपना अनूठा प्रकार देने में कोई समस्या नहीं देखी। लेकिन टीबीएच आप वास्तव में "सी / सी ++ प्रकार प्रणाली" के बारे में एक टिप्पणी में बहुत अधिक अंतर्दृष्टि प्राप्त करने की उम्मीद नहीं कर सकते हैं जैसे कि दो एक प्रकार की प्रणाली साझा करते हैं।
MSalters

2
@JDB - नहीं, यह नहीं है। समान भी नहीं है।
13द्रालो

जवाबों:


152

प्राथमिकताओं, जैसे stringया int, का व्यावसायिक डोमेन में कोई अर्थ नहीं है। इसका एक सीधा परिणाम यह है कि आप किसी URL का गलती से उपयोग कर सकते हैं जब कोई उत्पाद ID अपेक्षित होता है, या मूल्य की अपेक्षा करते समय मात्रा का उपयोग करता है

यही कारण है कि वस्तु Calisthenics चुनौती की विशेषता है कि इसके नियमों में से एक के रूप में रैपिंग की प्रधानता है:

नियम 3: सभी आदिम और तार लपेटें

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

वही दस्तावेज़ बताता है कि एक अतिरिक्त लाभ है:

आवर या मनी जैसी छोटी वस्तुएं भी हमें व्यवहार में लाने के लिए एक स्पष्ट स्थान प्रदान करती हैं जो अन्यथा अन्य वर्गों के आसपास होती

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

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

दोष और एक ही तर्क ऑब्जेक्ट कैलिसिथनिक्स अभ्यास के हर नियम पर लागू होता है - यह है कि अगर जल्दी से सब कुछ के लिए एक वर्ग बनाने के लिए बहुत भारी हो जाता है । अगर Productहोता है ProductPriceजो विरासत में से PositivePriceजो विरासत में से Priceहै जो बदले में से विरासत Money, यह साफ वास्तुकला, बल्कि एक पूरी गड़बड़ आदेश एक भी बात खोजने के लिए, एक मेंटेनर कुछ दर्जन हर बार फ़ाइलें खोलना चाहिए जहां है।

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

  • संपत्ति पाने वाला,
  • इसका समर्थन क्षेत्र,
  • एक निर्माता जो बैकिंग क्षेत्र के लिए मान प्रदान करता है,
  • एक प्रथा ToString(),
  • XML प्रलेखन टिप्पणियां (जो बहुत सारी लाइनें बनाती हैं),
  • Equalsऔर GetHashCodeओवरराइड्स (एलओसी का एक बहुत)।

और अंत में, जब प्रासंगिक:

  • एक डिबगरडिजप्ले विशेषता,
  • ==और !=ऑपरेटरों का ओवरराइड ,
  • अंतत: अंतर्निहित रूपांतरण ऑपरेटर का एक अधिभार मूल रूप से और इनकैप्सुलेटेड प्रकार से परिवर्तित करने के लिए,
  • कोड अनुबंध (आवधिक सहित, जो एक लंबी विधि है, इसकी तीन विशेषताओं के साथ),
  • कई कन्वर्टर्स जो XML क्रमांकन, JSON क्रमांकन या एक डेटाबेस से / के लिए एक मान को संग्रहीत / लोड करने के लिए उपयोग किया जाएगा।

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

निष्कर्ष:

  • उन प्राइमरी को उन कक्षाओं में लपेटें, जिनका एप्लिकेशन के व्यवसायिक डोमेन में अर्थ होता है जब (1) यह गलतियों को कम करने में मदद करता है, (2) कोड के दोहराव के जोखिम को कम करता है या (3) बाद में अंतर्निहित प्रकार को बदलने में मदद करता है।

  • अपने कोड में आपके द्वारा पाए जाने वाले प्रत्येक आदिम को स्वचालित रूप से न लपेटें: ऐसे कई मामले हैं जहां उपयोग करना stringया intपूरी तरह से ठीक है।

व्यवहार में public string CreateNewThing(), मदद ThingIdकरने के बजाय कक्षा का एक उदाहरण लौटाने में string, लेकिन आप यह भी कर सकते हैं:

  • Id<string>कक्षा का एक उदाहरण लौटाएं , जो सामान्य प्रकार का एक संकेत है जो यह दर्शाता है कि अंतर्निहित प्रकार एक स्ट्रिंग है। आपके पास पठनीयता का आपका लाभ है, बिना किसी प्रकार के बहुत कम बनाए रखने के लिए।

  • Thingकक्षा का एक उदाहरण लौटाएँ । यदि उपयोगकर्ता को केवल आईडी की आवश्यकता है, तो यह आसानी से किया जा सकता है:

    var thing = this.CreateNewThing();
    var id = thing.Id;
    

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

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

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

3
@ArTs: यह "चलो उपकरण की निंदा करते हैं क्योंकि कुछ लोग इसका गलत तरीके से उपयोग करते हैं" तर्क।
ब्लरफ्ल

6
@ मेनमा एक उदाहरण है जहाँ अर्थ के लिए एक महंगी त्रुटि से बचा जा सकता है: en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_failure
cbojar

60

मैं गुंजाइश को अंगूठे के नियम के रूप में उपयोग करूंगा : इस तरह के उत्पादन और उपभोग की गुंजाइश जितनी valuesकम होगी, आपको इस मूल्य का प्रतिनिधित्व करने वाली वस्तु बनाने की संभावना कम होगी।

कहें कि आपके पास निम्नलिखित छद्म कोड हैं

id = generateProcessId();
doFancyOtherstuff();
job.do(id);

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


14
एक बहुत अच्छा बिंदु। स्पष्ट प्रकार इरादे को संप्रेषित करने के लिए एक महत्वपूर्ण उपकरण है , जो विशेष रूप से वस्तु और सेवा सीमाओं के पार महत्वपूर्ण है।
अवनर शाहर-कश्तन

+1 हालांकि अगर आपने अभी तक doFancyOtherstuff()सबरूटीन के सभी कोड को रिफैक्ट नहीं किया है, तो आप सोच सकते हैं कि job.do(id)संदर्भ एक साधारण स्ट्रिंग के रूप में रखने के लिए पर्याप्त स्थानीय नहीं है।
मार्क हर्ड

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

34

स्टेटिक टाइप सिस्टम डेटा के गलत उपयोग को रोकने के बारे में हैं।

इस प्रकार के स्पष्ट उदाहरण हैं:

  • आप एक UUID का महीना नहीं प्राप्त कर सकते
  • आप दो तार गुणा नहीं कर सकते।

और अधिक सूक्ष्म उदाहरण हैं

  • आप डेस्क की लंबाई का उपयोग करके कुछ के लिए भुगतान नहीं कर सकते
  • आप URL के रूप में किसी के नाम का उपयोग करके HTTP अनुरोध नहीं कर सकते।

हमें doubleकीमत और लंबाई दोनों के लिए उपयोग करने के लिए लुभाया जा सकता है , या stringनाम और URL दोनों के लिए उपयोग किया जा सकता है । लेकिन ऐसा करने से हमारी भयानक प्रकार की प्रणाली खराब हो जाती है, और ये दुरुपयोग भाषा की स्थैतिक जाँच को पारित करने की अनुमति देता है।

न्यूटन-सेकंड के साथ भ्रमित होने वाले पाउंड-सेकंड के खराब होने के परिणाम खराब हो सकते हैं ।


यह विशेष रूप से तार के साथ एक समस्या है। वे अक्सर "सार्वभौमिक डेटा प्रकार" बन जाते हैं।

हम मुख्य रूप से कंप्यूटर के साथ पाठ इंटरफेस का उपयोग करते हैं, और हम अक्सर इन मानवीय इंटरफेस (UIs) को प्रोग्रामिंग इंटरफेस (API) तक बढ़ाते हैं । हम पात्रों के रूप में 34.25 के बारे में सोच 34.25 । हम पात्रों के रूप में एक तारीख के बारे में सोचते हैं 05-03-2015 । हम UUID को 75e945ee-f1e9-11e4-b9b2-1697f925ec7b अक्षर मानते हैं

लेकिन यह मानसिक मॉडल एपीआई एब्सट्रैक्ट को परेशान करता है।

शब्द या भाषा, जैसा कि वे लिखे या बोले गए हैं, मेरे विचार के तंत्र में कोई भूमिका नहीं लगती है।

अल्बर्ट आइंस्टीन

इसी प्रकार, पाठात्मक अभ्यावेदन को डिजाइनिंग प्रकार और एपीआई में कोई भूमिका नहीं निभानी चाहिए। खबरदार string! (और अन्य पीढ़ी सामान्य "आदिम" प्रकार)


प्रकार "संचार क्या समझ में आता है।"

उदाहरण के लिए, मैंने एक बार HTTP REST API के क्लाइंट पर काम किया। ठीक से, ठीक से किया गया, हाइपरमीडिया संस्थाओं का उपयोग करें, जिनके पास संबंधित संस्थाओं को इंगित करने वाले हाइपरलिंक हैं। इस क्लाइंट में, न केवल टाइपिंग की गई इकाइयाँ (जैसे उपयोगकर्ता, खाता, सदस्यता), उन संस्थाओं के लिंक भी टाइप किए गए थे (UserLink, AccountLink, SubscriptionLink)। लिंक लगभग रैपर से अधिक थे Uri, लेकिन अलग-अलग प्रकारों ने उपयोगकर्ता को लाने के लिए अकाउंटलिंक का उपयोग करने की कोशिश करना असंभव बना दिया। अगर सब कुछ सादा था Uri- या इससे भी बुरा, string- ये गलतियाँ केवल रनटाइम के दौरान होंगी।

इसी तरह, आपकी स्थिति में, आपके पास डेटा है जो केवल एक ही उद्देश्य के लिए उपयोग किया जाता है: एक की पहचान करने के लिए Operation। इसका उपयोग किसी और चीज के लिए नहीं किया जाना चाहिए, और हमने उन Operationयादृच्छिक तारों के साथ पहचान करने की कोशिश नहीं की है जिन्हें हमने बनाया है। एक अलग वर्ग बनाना आपके कोड में पठनीयता और सुरक्षा जोड़ता है।


बेशक, सभी अच्छी चीजों का उपयोग अधिक मात्रा में किया जा सकता है। विचार करें

  1. आपके कोड में कितनी स्पष्टता है

  2. इसका उपयोग कितनी बार किया जाता है

यदि डेटा का एक "प्रकार" (अमूर्त अर्थ में) अक्सर उपयोग किया जाता है, अलग-अलग उद्देश्यों के लिए, और कोड इंटरफेस के बीच, यह वर्बोसिटी की कीमत पर एक अलग वर्ग होने के लिए एक बहुत अच्छा उम्मीदवार है।


21
"तार अक्सर 'सार्वभौमिक' डेटा प्रकार बन जाते हैं" - यह जीभ की गाल की उत्पत्ति है "कड़ाई से टाइप की गई भाषाएं" मॉनीकर।
MSalters

@MSalters, हा हा, बहुत अच्छा।
पॉल ड्रेपर

4
और निश्चित रूप से, जब एक तारीख के रूप में व्याख्या की जाती 05-03-2015 है तो इसका क्या मतलब है ?
एक CVn

10

क्या आपको लगता है कि सुरक्षा कारणों से एक वर्ग में सरल प्रकार लपेटना एक अच्छा अभ्यास है?

कभी कभी।

यह उन मामलों में से एक है जहां आपको उन समस्याओं को तौलना होगा जो stringएक अधिक ठोस के बजाय उपयोग करने से उत्पन्न हो सकती हैं OperationIdentifier। उनकी गंभीरता क्या है? उनकी संभावना क्या है?

फिर आपको दूसरे प्रकार के उपयोग की लागत पर विचार करने की आवश्यकता है। इसका इस्तेमाल कितना दर्दनाक है? इसे बनाने में कितना काम है?

कुछ मामलों में, आप काम करने के लिए एक अच्छा ठोस प्रकार होने से अपने आप को समय और प्रयास बचाएंगे। दूसरों में, यह परेशानी के लायक नहीं होगा।

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


10

मैं आम तौर पर सहमत हूं कि कई बार आपको आदिम और तार के लिए एक प्रकार बनाना चाहिए, लेकिन क्योंकि उपरोक्त उत्तर ज्यादातर मामलों में एक प्रकार बनाने की सलाह देते हैं, मैं कुछ कारणों की सूची दूंगा क्यों / जब नहीं:

  • प्रदर्शन। मुझे यहां वास्तविक भाषाओं का उल्लेख करना चाहिए। C # में, यदि कोई क्लाइंट आईडी छोटा है और आप इसे एक कक्षा में लपेटते हैं - आपने अभी बहुत अधिक ओवरहेड बनाया है: मेमोरी, क्योंकि यह अब 64 बिट सिस्टम पर 8 बाइट्स है और अब से यह ढेर पर आवंटित किया गया है।
  • जब आप प्रकार पर धारणा बनाते हैं। यदि एक क्लाइंट आईडी एक छोटी है और आपके पास कुछ तर्क हैं जो इसे किसी तरह से पैक करते हैं - आप आमतौर पर पहले से ही प्रकार पर धारणा बनाते हैं। उन सभी जगहों पर अब आपको अमूर्तता को तोड़ना होगा। यदि यह एक जगह है, तो यह कोई बड़ी बात नहीं है, अगर यह सब जगह है, तो आप पा सकते हैं कि आप जिस समय का उपयोग कर रहे हैं वह आधा समय है।
  • क्योंकि हर भाषा में टाइफाइड नहीं होता। और उन भाषाओं के लिए जो कोड और पहले से ही लिखे गए हैं, ऐसे परिवर्तन करना एक बड़ा काम हो सकता है जो बग को भी लागू कर सकता है (लेकिन सभी के पास अच्छे कवरेज के साथ एक परीक्षण सूट है?)।
  • कुछ मामलों में यह पठनीयता कम कर देता है। मैं इसे कैसे प्रिंट करूं? मैं इसे कैसे मान्य करूं? क्या मुझे अशक्त के लिए जाँच करनी चाहिए? क्या वे सभी प्रश्न हैं जिनकी आपको टाइप की परिभाषा में ड्रिल करने की आवश्यकता है।

3
निश्चित रूप से यदि आवरण प्रकार एक वर्ग के बजाय एक संरचना है, तो एक short(उदाहरण के लिए) एक ही लागत लिपटे या अलिखित है। (?)
मैथमैटिकलऑर्चिड

1
क्या यह एक प्रकार के लिए अच्छा डिजाइन नहीं होगा जो अपनी मान्यता को अलग कर दे? या इसे मान्य करने के लिए एक सहायक प्रकार बनाने के लिए?
निक उडेल

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

7

नहीं, आपको "सब कुछ" के लिए प्रकार (कक्षाएं) को परिभाषित नहीं करना चाहिए।

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

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

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


5

सतह पर ऐसा लगता है कि आपको बस एक ऑपरेशन की पहचान करनी है।

इसके अतिरिक्त आप कहते हैं कि एक ऑपरेशन क्या करना चाहिए:

ऑपरेशन को शुरू करने के लिए [और] इसकी समाप्ति पर नजर रखने के लिए

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

इसे कहते हैं

कमांड पैटर्न [...] का उपयोग किसी कार्रवाई को करने या बाद में किसी घटना को ट्रिगर करने के लिए आवश्यक सभी सूचनाओं को एन्कैप करने के लिए किया जाता है ।

मुझे लगता है कि आप अपने कार्यों के साथ क्या करना चाहते हैं, इसकी तुलना में यह बहुत समान है। (उन वाक्यांशों की तुलना करें, जिन्हें मैंने दोनों उद्धरणों में बोल्ड किया था) एक स्ट्रिंग को वापस करने के बजाय, Operationसार अर्थ में एक पहचानकर्ता को लौटाएं, उदाहरण के लिए oop में उस वर्ग के ऑब्जेक्ट के लिए एक संकेतक।

टिप्पणी के संबंध में

इस वर्ग को कमांड कहना wtf-y होगा और फिर इसके अंदर तर्क नहीं होगा।

नहीं, यह नहीं होगा। याद रखें कि पैटर्न बहुत सार हैं , वास्तव में इतना सार है कि वे कुछ हद तक मेटा हैं। यही है, वे अक्सर प्रोग्रामिंग को सार करते हैं और कुछ वास्तविक दुनिया की अवधारणा नहीं। कमांड पैटर्न एक फंक्शन कॉल का एक अमूर्त हिस्सा है। (या विधि) मानो किसी ने ठहराव बटन को हिट किया है ठीक मापदंडों के मूल्यों को पारित करने के बाद और निष्पादन से ठीक पहले, बाद में फिर से शुरू करने के लिए।

निम्नलिखित ऊप पर विचार कर रहा है, लेकिन इसके पीछे की प्रेरणा किसी भी प्रतिमान के लिए सही होनी चाहिए। मुझे कुछ कारण देना पसंद है कि तर्क को कमान में रखना एक बुरी बात क्यों मानी जा सकती है।

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

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


क्योंकि पैटर्न अमूर्त हैं, इसलिए अच्छी वास्तविक दुनिया के रूपकों के साथ आना मुश्किल हो सकता है। यहाँ एक प्रयास है:

"अरे दादी, क्या आप टीवी पर रिकॉर्ड बटन को 12 बजे हिट कर सकते हैं ताकि मैं चैनल 1 पर simpsons को याद न करूं?"

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


आप सही हैं, मैंने इसके बारे में ऐसा नहीं सोचा है। लेकिन कमांड पैटर्न 100% अच्छा नहीं है क्योंकि ऑपरेशन का तर्क किसी अन्य वर्ग में समझाया गया है और मैं इसे कमांड के ऑब्जेक्ट के अंदर नहीं डाल सकता। इस वर्ग को कमांड कहना wtf-y होगा और फिर इसके अंदर तर्क नहीं होगा।
ज़िव

इसके बहुत सारे अर्थ निकलते हैं। एक ऑपरेशन को वापस करने पर विचार करें, एक ऑपरेशनआईडेंटिफायर नहीं। यह C # TPL के समान है जहाँ आप कार्य या कार्य <T> लौटाते हैं। @Ziv: आप कहते हैं "ऑपरेशन का तर्क किसी अन्य वर्ग में समझाया गया है।" लेकिन क्या इसका मतलब यह है कि आप इसे यहां से भी उपलब्ध नहीं करा सकते?
मोबी डिस्क

@Ziv मैं अलग करने के लिए भीख माँगती हूँ। मेरे जवाब में जोड़े गए कारणों पर एक नज़र डालें और देखें कि क्या वे आपसे कोई मतलब रखते हैं। =)
अशक्त

5

आदिम प्रकारों को लपेटने के पीछे आइडिया,

  • डोमेन विशिष्ट भाषा स्थापित करने के लिए
  • गलत मानों को पारित करके उपयोगकर्ताओं द्वारा की गई गलतियों को सीमित करें

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

उदाहरण के लिए यदि आपके पास वर्ग क्रम है,

Order
{
   long OrderId { get; set; }
   string InvoiceNumber { get; set; }
   string Description { get; set; }
   double Amount { get; set; }
   string CurrencyCode { get; set; }
}

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

तो, केवल ऑर्डरआईडी, इनवॉइसनंबर को लपेटना और मुद्रा के लिए एक समग्र प्रस्तुत करना इस परिदृश्य में समझ में आता है और संभवतः रैपिंग विवरण का कोई मतलब नहीं है। इसलिए पसंदीदा परिणाम दिख सकता है,

    Order
    {
       OrderIdType OrderId { get; set; }
       InvoiceNumberType InvoiceNumber { get; set; }
       string Description { get; set; }
       Currency Amount { get; set; }
    }

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


4

अलोकप्रिय राय:

आपको आमतौर पर एक नए प्रकार को परिभाषित नहीं करना चाहिए!

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

छद्म प्रकार सामान्य पुस्तकालय कार्यक्षमता को बेकार बनाते हैं।

जावा के गणित कार्य सभी संख्याओं के साथ काम कर सकते हैं। लेकिन अगर आप एक नए वर्ग के प्रतिशत को परिभाषित करते हैं (एक दोहरा लपेट जो 0 ~ 1 की सीमा में हो सकता है) तो ये सभी कार्य बेकार हैं और कक्षाओं द्वारा लपेटे जाने की आवश्यकता है (और भी बदतर) प्रतिशत वर्ग के आंतरिक प्रतिनिधित्व के बारे में जानने की आवश्यकता है ।

छद्म प्रकार वायरल जाते हैं

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

संदेश छीन लो

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

एक उदाहरण:

A uintपूरी तरह से एक UserId का प्रतिनिधित्व कर सकता है, हम जावा के ऑपरेटरों के लिए uints (जैसे ==) का उपयोग कर सकते हैं और हमें उपयोगकर्ता आईडी की 'आंतरिक स्थिति' की सुरक्षा के लिए व्यावसायिक तर्क की आवश्यकता नहीं है।


इस बात से सहमत। सभी प्रोग्रामिंग दर्शन ठीक है, लेकिन व्यवहार में आपको इसे भी काम करना होगा
इवान

यदि आपने ब्रिटेन में सबसे गरीब लोगों के लिए ऋणों के लिए कोई विज्ञापन देखा है, तो आप पाएंगे कि प्रतिशत
0.

1
C / C ++ / Objective C में आप एक टाइप्डिफ का उपयोग कर सकते हैं, जो आपको मौजूदा आदिम प्रकार के लिए एक नया नाम देता है। दूसरी ओर, आपके कोड को कोई फर्क नहीं पड़ता है कि अंतर्निहित प्रकार क्या है, उदाहरण के लिए, अगर मैं uint32_t से uint64_t से आदेश परिवर्तित करता हूं (क्योंकि मुझे 4 बिलियन से अधिक ऑर्डर संसाधित करने की आवश्यकता है)।
gnasher729

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

@ gnasher729: C ++ 11 में उपयोगकर्ता-परिभाषित शाब्दिक शब्द भी हैं जो उपयोगकर्ता के लिए रैपिंग प्रक्रिया को बहुत मधुर बनाते हैं: दूरी d = 36.0_mi + 42.0_km; msdn.microsoft.com/en-us/library/dn919277.aspx
damix911

3

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

NamingConvention पठनीयता के लिए महत्वपूर्ण है। दोनों संयुक्त इरादे स्पष्ट रूप से व्यक्त कर सकते हैं।
लेकिन /// अभी भी उपयोगी है।

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


2
क्या ///मतलब है?
गाबे

1
/// C # में दस्तावेज़ीकरण टिप्पणी है जो कॉल पद्धति बिंदु पर हस्ताक्षर के प्रलेखन को दिखाने की अनुमति देता है। दस्तावेज़ कोड के सर्वोत्तम तरीके पर विचार करें। औजारों द्वारा खेती की जा सकती है और यह प्रस्ताव अंतर्मुखी व्यवहार तक पहुंच सकता है। msdn.microsoft.com/en-us/library/tkxs89c5%28v=vs.71%29.aspx
phil soady
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.