अगर मुझे पता है कि विधि खराब इनपुट वापस नहीं कर सकती है, तो क्या मुझे विधि कॉल के रिटर्न मान को मान्य करना चाहिए?


30

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

दिया हुआ

User getUser(Int id)
{
    User temp = new User(id);
    temp.setName("John");

    return temp;
}

क्या मुझे करना चाहिए

void myMethod()
{
    User user = getUser(1234);
    System.out.println(user.getName());
}

या

void myMethod()
{
    User user = getUser(1234);

    // Validating
    Preconditions.checkNotNull(user, "User can not be null.");
    Preconditions.checkNotNull(user.getName(), "User's name can not be null.");

    System.out.println(user.getName());
}

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


सभी उत्तरों से मेरा निष्कर्ष (अपने स्वयं के लिए स्वतंत्र महसूस करें):

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

1
उस% 100 कोड कवरेज के लिए निशाना लगाओ!
जारेड ब्रीड्स

9
आप सिर्फ एक समस्या ( Null) पर ध्यान क्यों दे रहे हैं ? यह शायद उतना ही समस्याग्रस्त है अगर नाम है ""(शून्य नहीं है लेकिन खाली स्ट्रिंग है) या "N/A"। या तो आप परिणाम पर भरोसा कर सकते हैं, या आपको उचित रूप से पागल होना होगा।
MSalters

3
हमारे कोडबेस में हमारे पास एक नामकरण योजना है: getFoo () शून्य वापस नहीं करने का वादा करता है, और getFooIfPresent () शून्य वापस कर सकता है।
pjc50

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

जवाबों:


42

यह इस बात पर निर्भर करता है कि गेटअप और मायमेथोड को बदलने की कितनी संभावना है , और इससे भी महत्वपूर्ण बात यह है कि वे एक दूसरे से स्वतंत्र रूप से बदलने की कितनी संभावना है

यदि आप किसी तरह से यह निश्चित रूप से जानते हैं कि भविष्य में कभी भी, कभी भी, कभी भी परिवर्तन नहीं होगा, तो हाँ यह समय बर्बाद करने वाला है, जितना कि यह मान्य करने के लिए समय बर्बाद करना है कि iएक i = 3;बयान के तुरंत बाद 3 का मूल्य है । वास्तव में, आप यह नहीं जानते। लेकिन कुछ चीजें हैं जो आप जानते हैं:

  • क्या ये दो कार्य "एक साथ रहते हैं"? दूसरे शब्दों में, क्या उनके पास वही लोग हैं जो उन्हें बनाए रखते हैं, क्या वे एक ही फ़ाइल का हिस्सा हैं, और इस प्रकार वे एक दूसरे के साथ "सिंक" में रहने की संभावना रखते हैं? इस मामले में यह शायद सत्यापन जांच जोड़ने के लिए ओवरकिल है, क्योंकि इसका मतलब है कि अधिक कोड का मतलब है (और संभवतः स्पॉन बग) को हर बार दो कार्यों को बदलने या अलग-अलग संख्या में कार्यों में रिफैक्ट हो जाते हैं।

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

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

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


2
इसके अलावा: यदि आप getUserबाद में बदलना चाहते थे , ताकि यह अशक्त हो सके, तो क्या स्पष्ट जाँच आपको वह जानकारी देगी जो आपको "NullPointerException" और लाइन नंबर से नहीं मिल सकती है?
user253751

ऐसा लगता है कि दो चीजें हैं जो आप मान्य कर सकते हैं: (1) यह विधि ठीक से काम करती है, जैसे कि इसमें कोई बग नहीं है। (२) यह विधि आपके अनुबंध का सम्मान करती है। मैं ओवरकिल होने के लिए # 1 को मान्य करते हुए देख सकता हूं। आपको इसके बजाय # 1 करने वाले परीक्षण करने चाहिए। यही कारण है कि मैं i = 3 को मान्य नहीं करता; तो मेरा प्रश्न # 2 से संबंधित है। मुझे उस के लिए आपका उत्तर पसंद है, लेकिन एक ही समय में, यह आपके निर्णय के जवाब का उपयोग है। क्या आप किसी अन्य समस्या को स्पष्ट रूप से अपने अनुबंधों को वैधता से उत्पन्न करते हुए देख रहे हैं और फिर समय लिखने वाले को थोड़ा समय बर्बाद कर रहे हैं?
डिडियर ए

एकमात्र अन्य "समस्या" यह है कि यदि अनुबंध की आपकी व्याख्या गलत है, या गलत हो गई है, तो आपको सभी सत्यापन को बदलना होगा। लेकिन यह अन्य सभी कोड पर भी लागू होता है।
Ixrec

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

22

Ixrec का उत्तर अच्छा है, लेकिन मैं एक अलग दृष्टिकोण लूंगा क्योंकि मेरा मानना ​​है कि यह विचार करने योग्य है। इस चर्चा के उद्देश्य के लिए मैं दावे के बारे में बात करूंगा, क्योंकि यह वह नाम है जिसके द्वारा आपकाPreconditions.checkNotNull() पारंपरिक रूप से जाने जाते हैं।

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

मेरा लक्ष्य है:

सवाल जो आपको हमेशा अपने आप से पूछना चाहिए वह यह है कि "क्या मुझे इस पर जोर नहीं देना चाहिए?" लेकिन "कुछ ऐसा है जिसे मैं मुखर करना भूल गया?"

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

लेकिन इस नियम के अपवाद भी हैं। Ixrec का उदाहरण लेने के लिए पर्याप्त रूप से, एक प्रकार की स्थिति मौजूद है, जहां int i = 3;एक दावे के साथ पालन करना पूरी तरह से वांछनीय है जो iवास्तव में एक निश्चित सीमा के भीतर है। यह वह स्थिति है जहां iकिसी के द्वारा परिवर्तित किए जाने के लिए उत्तरदायी है जो विभिन्न-अगर परिदृश्यों की कोशिश कर रहा है, और जो कोड का अनुसरण करता है iवह एक निश्चित सीमा के भीतर मूल्य पर निर्भर करता है , और यह तुरंत निम्नलिखित कोड को देखकर तुरंत स्पष्ट नहीं होता है कि क्या स्वीकार्य सीमा है। तो,int i = 3; assert i >= 0 && i < 5; यह पहली बार बकवास लग सकता है, लेकिन अगर आप इसके बारे में सोचते हैं, तो यह आपको बताता है कि आप इसके साथ खेल सकते हैं i, और यह आपको वह सीमा भी बताता है जिसके भीतर आपको रहना चाहिए। एक दस्तावेज़ीकरण सबसे अच्छा प्रकार का प्रलेखन है, क्योंकियह मशीन द्वारा लागू किया जाता है , इसलिए यह एक सही गारंटी है, और यह कोड के साथ एक साथ रिफैक्ट हो जाता है , इसलिए यह हमेशा बना रहता है।

आपका getUser(int id)उदाहरण उदाहरण के सापेक्ष बहुत दूर का वैचारिक नहीं है assign-constant-and-assert-in-range। आप देखें, परिभाषा के अनुसार, कीड़े तब होते हैं जब चीजें व्यवहार का प्रदर्शन करती हैं जो उस व्यवहार से अलग होती है जिसकी हमें उम्मीद थी। सच है, हम सब कुछ मुखर नहीं कर सकते, इसलिए कभी-कभी कुछ डिबगिंग होगी। लेकिन यह उद्योग में एक अच्छी तरह से स्थापित तथ्य है कि जितनी जल्दी हम एक त्रुटि पकड़ते हैं, उतना ही कम खर्च होता है। आपके द्वारा पूछे जाने वाले प्रश्न केवल यह सुनिश्चित करने के लिए नहीं हैं कि आप कैसे हैं कि getUser()कभी भी अशक्त नहीं लौटेंगे, (और एक अशक्त नाम वाले उपयोगकर्ता को कभी नहीं लौटाएंगे), लेकिन यह भी कि कोड के बाकी हिस्सों के साथ किस तरह की बुरी चीजें होंगी। वास्तव में एक दिन कुछ अप्रत्याशित लौट आता है, और यह कितना आसान है कि बाकी कोड को देखकर ठीक से पता चल सके कि क्या अपेक्षित था getUser()

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

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


2
हाँ। इसे मुखर करें। मैं कमोबेश यही जवाब देने के लिए यहां आया हूं। ++
रबरडक

2
@SteveJessop मैं इसे सही करूंगा ... && sureness < 1)
माइक नाकिस

2
@ माइकाइकिस: यह हमेशा एक बुरा सपना होता है जब यूनिट परीक्षण लिखते हैं, इंटरफ़ेस द्वारा अनुमत वापसी मूल्य लेकिन वास्तव में किसी भी इनपुट से उत्पन्न करना असंभव;; वैसे भी, जब आप 101% सुनिश्चित हों कि आप सही हैं तो आप निश्चित रूप से गलत हैं !
स्टीव जेसप

2
+1 उन चीजों को इंगित करने के लिए जिन्हें मैं अपने उत्तर में उल्लेख करना भूल गया था।
Ixrec

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

8

एक निश्चित सं।

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

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

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


मैं सामान्य भावना से सहमत हूं, लेकिन ऐसी परिस्थितियां हैं जहां यह निश्चित रूप से रिटर्न वैल्यू को मान्य करने के लिए समझ में आता है। उदाहरण के लिए यदि आपकी बाहरी वेब सेवा पर कॉल करते हैं, तो आप कभी-कभी उत्तर के प्रारूप (xsd, आदि ...) को कम से कम सत्यापित करना चाहते हैं
AK_

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

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

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

5

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

यदि शून्य गेटअउसर विधि का एक वैध रिटर्न मान नहीं है, तो गेटवेसर में एक बग है - गेटअप विधि को एक अपवाद फेंकना चाहिए या अन्यथा तय किया जाना चाहिए।

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


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

और क्या होगा अगर getUser या user.getName अपवादों को फेंकने के लिए बदल जाए? आपके पास एक जांच होनी चाहिए, लेकिन उपयोगकर्ता के उपयोग की विधि के रूप में नहीं। GetUser विधि को लपेटें - और यहां तक ​​कि उपयोगकर्ता वर्ग को भी - अपने अनुबंधों को लागू करने के लिए, यदि आप getUser कोड ब्रेकिंग के भविष्य के परिवर्तनों के बारे में चिंतित हैं। वर्ग के व्यवहार के बारे में अपनी मान्यताओं की जांच करने के लिए इकाई परीक्षण भी बनाएं।
मैथ्यू

@didibus अपने उत्तर को स्पष्ट करने के लिए ... एक स्माइली इमोटिकॉन गेटअसर का वैध रिटर्न मूल्य नहीं है। गेटउज़र का निरीक्षण करके, मैंने देखा कि कार्यान्वयन एक स्माइली इमोटिकॉन कभी नहीं लौटाएगा । मेरा सवाल यह है कि क्या मुझे अपने निरीक्षण पर भरोसा करना चाहिए और मेरी पद्धति में जांच नहीं होनी चाहिए, या क्या मुझे अपने निरीक्षण पर संदेह करना चाहिए, और अभी भी एक जांच है। यह भविष्य में विधि में बदलाव भी संभव है, एक स्माइली इमोटिकॉन वापस न करने की मेरी उम्मीदों को तोड़ते हुए । कॉल करने वाले का काम यह पुष्टि करना नहीं है कि कॉल किया गया फ़ंक्शन उसके अनुबंध को पूरा कर रहा है।
विंस ओ'सुल्लिवन

@ VinceO'Sullivan ऐसा लगता है कि "अनुबंध" मुद्दे के केंद्र में है। और मेरा प्रश्न निहित अनुबंधों के बारे में है, बनाम स्पष्ट। एक विधि जो int को वापस करती है मैं अभिप्रेरित करता हूं कि मुझे एक स्ट्रिंग नहीं मिल रही है। लेकिन, अगर मुझे केवल सकारात्मक स्याही चाहिए, तो क्या मुझे चाहिए? यह केवल निहित है कि विधि नकारात्मक इंट वापस नहीं आती है, क्योंकि मैंने इसका निरीक्षण किया था। यह हस्ताक्षर या प्रलेखन से स्पष्ट नहीं है कि यह नहीं करता है।
डिडियर ए

1
इससे कोई फर्क नहीं पड़ता कि अनुबंध निहित है या स्पष्ट है। यह पुष्टि करने के लिए कॉलिंग कोड का काम नहीं है कि वैध डेटा दिए जाने पर कॉल विधि वैध डेटा लौटाती है। आप उदाहरण में, आप जानते हैं कि नकारात्मक init गलत उत्तर नहीं हैं, लेकिन क्या आप जानते हैं कि सकारात्मक int सही हैं? यह साबित करने के लिए कि आपको किस विधि से काम करना है, आपको वास्तव में कितने परीक्षणों की आवश्यकता है? एकमात्र सही पाठ्यक्रम यह मान लेना है कि विधि सही है।
विंस ओ'सलीवन

5

मैं तर्क दूंगा कि आपके प्रश्न का आधार बंद है: क्यों एक अशक्त संदर्भ का उपयोग करें?

अशक्त वस्तु पैटर्न वस्तुओं है कि अनिवार्य रूप से कुछ भी नहीं वापस जाने के लिए एक रास्ता है: "। कोई उपयोगकर्ता" के बजाय अपने उपयोगकर्ता के लिए बदले अशक्त से, एक वस्तु का प्रतिनिधित्व वापसी

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

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

यहाँ null के लिए कोड जाँच का एक उदाहरण दिया गया है:

User u = getUser();
String displayName = "";
if (u != null) {
  displayName = u.getName();
}
return displayName;

यहाँ एक अशक्त वस्तु का उपयोग कर कोड का एक उदाहरण दिया गया है:

return getUser().getName();

जो स्पष्ट है? मेरा मानना ​​है कि दूसरा है।


हालांकि प्रश्न को टैग किया गया है , यह ध्यान देने योग्य है कि संदर्भ का उपयोग करते समय नल ऑब्जेक्ट पैटर्न सी ++ में वास्तव में उपयोगी है। जावा संदर्भ C ++ पॉइंटर्स की तरह अधिक हैं, और शून्य की अनुमति देते हैं। C ++ संदर्भ धारण नहीं कर सकता nullptr। यदि कोई C ++ में शून्य संदर्भ के लिए कुछ अनुरूप होना चाहता है, तो नल ऑब्जेक्ट पैटर्न ही एकमात्र तरीका है जिसे मैं पूरा करना चाहता हूं।


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

1
कोई विधि गलत मान क्यों लौटाएगी? एकमात्र जगह जिसे यह जांचना चाहिए वह आपके आवेदन की सीमा पर है: उपयोगकर्ता के साथ और अन्य प्रणालियों के साथ इंटरफेस। अन्यथा, यही कारण है कि हमारे पास अपवाद हैं।

मेरी कल्पना करो: int i = getCount; फ्लोट x = 100 / i; अगर मुझे पता है कि getCount 0 नहीं लौटाता है, क्योंकि मैंने या तो विधि लिखी है या इसका निरीक्षण किया है, क्या मुझे 0 के लिए चेक छोड़ना चाहिए?
डिडियर ए।

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

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

1

आम तौर पर, मैं कहूंगा कि मुख्य रूप से निम्नलिखित तीन पहलुओं पर निर्भर करता है:

  1. मजबूती: क्या कॉलिंग विधि nullमूल्य के साथ सामना कर सकती है ? यदि एक nullमूल्य के परिणामस्वरूप RuntimeExceptionमैं एक चेक की सिफारिश कर सकता हूं - जब तक कि जटिलता कम न हो और कॉलिंग / कॉलिंग विधि एक ही लेखक द्वारा बनाई गई हो, और nullअपेक्षित नहीं है (उदाहरण दोनों privateएक ही पैकेज में)।

  2. कोड की जिम्मेदारी: यदि डेवलपर ए getUser()विधि के लिए जिम्मेदार है , और डेवलपर बी इसका उपयोग करता है (जैसे एक पुस्तकालय के भाग के रूप में), तो मैं इसके मूल्य को मान्य करने की जोरदार सिफारिश करूंगा। सिर्फ इसलिए कि डेवलपर बी को एक बदलाव के बारे में पता नहीं है जिसके परिणामस्वरूप संभावित nullवापसी मूल्य हो सकता है।

  3. जटिलता: कार्यक्रम या पर्यावरण की समग्र जटिलता जितनी अधिक होगी, उतना ही अधिक मैं रिटर्न वैल्यू को मान्य करने की सिफारिश करूंगा। यहां तक ​​कि अगर आपको लगता है कि यह nullकॉलिंग पद्धति के संदर्भ में आज नहीं हो सकता है, तो यह हो सकता है कि आपको getUser()किसी अन्य उपयोग के मामले में बदलाव करना पड़े । एक बार कुछ महीने या साल चले जाते हैं, और कोड की कुछ हज़ार लाइनें जोड़ दी जाती हैं, यह काफी मुश्किल हो सकता है।

इसके अलावा, मैं nullJavaDoc टिप्पणी में संभावित रिटर्न मानों को दस्तावेज़ित करने की सलाह दूंगा। सबसे IDE में JavaDoc विवरणों को उजागर करने के कारण, यह जो भी उपयोग करता है उसके लिए एक उपयोगी चेतावनी हो सकती है getUser()

/** Returns ....
  * @param: id id of the user
  * @return: a User instance related to the id;
  *          null, if no user with identifier id exists
 **/
User getUser(Int id)
{
    ...
}

-1

आप निश्चित रूप से नहीं है।

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


1
मुझे पता है, लेकिन केवल इसलिए कि मैंने दूसरे तरीके के कार्यान्वयन का निरीक्षण किया या लिखा। विधि का अनुबंध स्पष्ट रूप से यह नहीं कहता है कि यह नहीं हो सकता। इसलिए, यह, उदाहरण के लिए, भविष्य में बदल सकता है। या इसमें एक बग हो सकता है जो एक अशक्त का कारण बनता है भले ही वह कोशिश न कर रहा हो।
डिडियर ए
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.