क्या एक अपवाद को एक विरोधी पैटर्न यहाँ फेंक रहा है?


33

मुझे कोड समीक्षा के बाद एक डिज़ाइन विकल्प पर बस चर्चा करनी थी। मुझे आश्चर्य है कि आपकी क्या राय है।

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

पर चर्चा की समाधान निम्नलिखित पैटर्न का इस्तेमाल (नोट: यह वह जगह है नहीं वास्तविक कोड, स्पष्ट रूप से - यह निदर्शी प्रयोजनों के लिए सरल बनाया गया है):

public class Preferences {
    // null values are legal
    private Map<String, String> valuesFromDatabase;

    private static Map<String, String> defaultValues;

    class KeyNotFoundException extends Exception {
    }

    public String getByKey(String key) {
        try {
            return getValueByKey(key);
        } catch (KeyNotFoundException e) {
            String defaultValue = defaultValues.get(key);
            valuesFromDatabase.put(key, defaultvalue);
            return defaultValue;
        }
    }

    private String getValueByKey(String key) throws KeyNotFoundException {
        if (valuesFromDatabase.containsKey(key)) {
            return valuesFromDatabase.get(key);
        } else {
            throw new KeyNotFoundException();
        }
    }
}

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

यह अनिवार्य रूप से दो तरीके से खेल रहा है, केवल एक दूसरे से कुछ संवाद करने के लिए।

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

प्रतिवाद यह था कि getValueByKey- निजी पद्धति - जैसा कि अभी परिभाषित किया गया है, दोनों मूल्य के बारे में सार्वजनिक विधि को सूचित करने का कोई प्राकृतिक तरीका नहीं है , और क्या कुंजी थी। (यदि ऐसा नहीं था, तो इसे जोड़ना होगा ताकि मूल्य को अपडेट किया जा सके)।

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

getValueByKeyएक के कुछ प्रकार वापसी करना होगा Tuple<Boolean, String>ताकि हम बीच भेद कर सकते,, bool सही पर सेट किया है, तो कुंजी पहले से ही वहाँ है (true, null)और (false, null)। (एक outपैरामीटर C # में इस्तेमाल किया जा सकता है, लेकिन यह जावा है)।

क्या यह एक अच्छा विकल्प है? हां, आपको प्रभाव के लिए कुछ एकल-उपयोग वर्ग को परिभाषित करना होगा Tuple<Boolean, String>, लेकिन फिर हम छुटकारा पा रहे हैं KeyNotFoundException, ताकि इस तरह के शेष बाहर हो जाएं। हम एक अपवाद को संभालने के ओवरहेड से भी बच रहे हैं, हालांकि यह व्यावहारिक रूप से महत्वपूर्ण नहीं है - इसमें बोलने के लिए कोई प्रदर्शन विचार नहीं हैं, यह एक क्लाइंट ऐप है और यह ऐसा नहीं है कि उपयोगकर्ता की प्राथमिकताएं प्रति सेकंड लाखों बार पुनर्प्राप्त की जाएंगी।

इस दृष्टिकोण की भिन्नता Optional<String>कुछ रीति-रिवाजों के बजाय अमरूद का उपयोग कर सकती है (अमरूद पहले से ही परियोजना के दौरान प्रयोग किया जाता है) Tuple<Boolean, String>और फिर हम Optional.<String>absent()"उचित" के बीच अंतर कर सकते हैं null। यह अभी भी हैकिश महसूस करता है, हालांकि, उन कारणों के लिए जो देखने में आसान हैं - "शून्यता" के दो स्तरों का परिचय उस अवधारणा का दुरुपयोग करते हैं Optionalजो पहली जगह में एस बनाने के पीछे खड़ा था ।

एक अन्य विकल्प स्पष्ट रूप से जांचना होगा कि क्या कुंजी मौजूद है ( केवल एक boolean containsKey(String key)विधि जोड़ें और कॉल करें getValueByKeyयदि हमने पहले ही यह मान लिया है कि यह मौजूद है)।

अंत में, कोई निजी पद्धति को भी इनलाइन कर सकता है, लेकिन वास्तविक getByKeyमेरे कोड नमूने की तुलना में कुछ अधिक जटिल है, इस प्रकार इनलाइनिंग इसे काफी बुरा लगेगा।

मैं यहाँ बालों को विभाजित कर सकता हूं, लेकिन मैं उत्सुक हूं कि आप इस मामले में सबसे अच्छा अभ्यास करने के लिए सबसे करीब होंगे। मुझे Oracle के या Google के स्टाइल गाइड में कोई उत्तर नहीं मिला।

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


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

1
मैंने अपने वीटीसी को वापस ले लिया - आप से संबंधित कुछ के लिए पूछ रहे हैं, लेकिन मेरे द्वारा सुझाए गए डुप्लिकेट से अलग।

3
मुझे लगता है कि getValueByKeyसार्वजनिक होने पर सवाल और दिलचस्प हो जाता है।
डॉक ब्राउन

2
भविष्य के संदर्भ के लिए, आपने सही काम किया। यह कोड समीक्षा पर विषय से हटकर होता क्योंकि यह उदाहरण कोड है।
रबरडाक

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

जवाबों:


75

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

यह बहुत क्लीनर है तब आपका संस्करण ( getValueByKey()विधि निकाल दी जाती है):

public String getByKey(String key) {
    if (valuesFromDatabase.containsKey(key)) {
        return valuesFromDatabase.get(key);
    } else {
        String defaultValue = defaultValues.get(key);
        valuesFromDatabase.put(key, defaultvalue);
        return defaultValue;
    }
}

एक अपवाद केवल तभी फेंक दिया जाना चाहिए जब आप स्थानीय रूप से त्रुटि को हल करने के लिए नहीं जानते हैं।


14
जवाब के लिए धन्यवाद। रिकॉर्ड के लिए, मैं इस सहकर्मी हूं (मुझे मूल कोड पसंद नहीं आया), मैंने बस सवाल को न्यूट्रल किया ताकि यह लोड न हो :)
कोनराड मोरावस्की

59
पागलपन का पहला संकेत: आप खुद से बात करना शुरू करते हैं।
रॉबर्ट हार्वे

1
@ B @овиЈ: ठीक है, उस मामले में मुझे लगता है कि यह ठीक है, लेकिन क्या होगा अगर आपको दो वेरिएंट की आवश्यकता है - एक विधि लापता कुंजियों के स्वत: संस्कार के बिना मान प्राप्त कर रही है, और एक के साथ? आपको क्या लगता है कि तब सबसे स्वच्छ (और DRY) विकल्प क्या है?
डॉक ब्राउन

3
@RobertHarvey :) किसी और ने इस कोड ऑफ कोड को लिखा, एक वास्तविक अलग व्यक्ति, मैं समीक्षक था
कोनराड मोरावस्की

1
@ अलवारो, अपवादों का उपयोग अक्सर एक समस्या नहीं है। भाषा की परवाह किए बिना अपवादों का बुरी तरह से उपयोग करना एक समस्या है।
kdbanman

11

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

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


1
मुझे नहीं लगता कि Optionalअशक्त हो सकता है। Optional.of()केवल एक अशक्त संदर्भ लेता है और Optional.fromNullable()अशक्त को "मान मौजूद नहीं" के रूप में मानता है।
नवीन

1
@ यह शून्य नहीं पकड़ सकता है, लेकिन आप Optional.absent()अपने निपटान में है। और हां, तो Optional.fromNullable(string)बराबर होगा Optional.<String>absent()अगर stringअशक्त था, या Optional.of(string)अगर यह नहीं था।
कोनराड मोरावस्की

@KonradMorawski मैंने सोचा था कि ओपी में समस्या यह थी कि आप बिना किसी अपवाद के एक शून्य स्ट्रिंग और एक नोक्सिस्टेंट स्ट्रिंग के बीच अंतर नहीं कर सकते थे। Optional.absent()इनमें से एक परिदृश्य को शामिल किया गया। आप दूसरे का प्रतिनिधित्व कैसे करते हैं?
नवीन

@ नवीन एक वास्तविक के साथ null
कोनराड मोरावस्की

4
@KonradMorawski: यह एक बहुत बुरा विचार लगता है। मैं शायद ही यह कहने का एक स्पष्ट तरीका सोच सकता हूं कि "यह विधि कभी नहीं लौटती है null!" इसे वापस घोषित करने की तुलना में Optional<...>। । ।
ruakh

8

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

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

जैसा कि टिप्पणी में माइक ने कहा है, इसके साथ एक मुद्दा है; न तो अमरूद और न ही जावा 8 के Optionalभंडारण की अनुमति है null। इस प्रकार आपको अपना स्वयं का रोल करना होगा - जबकि सीधा - सरल है जिसमें बॉयलरप्लेट की एक उचित मात्रा शामिल है, इसलिए कुछ के लिए ओवरकिल हो सकता है जो केवल आंतरिक रूप से एक बार उपयोग किया जाएगा। आप नक्शे का प्रकार भी बदल सकते हैं Map<String, Optional<String>>, लेकिन हैंडलिंग बहुत Optional<Optional<String>>अजीब हो जाता है।

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


1
ठीक है, वास्तव में यह केवल Map<String, String>डेटाबेस टेबल स्तर पर है, क्योंकि valuesकॉलम एक प्रकार का होना है। हालांकि, प्रत्येक कुंजी-मूल्य जोड़ी को मजबूत-टाइप करने वाली DAO परत है। लेकिन मैंने स्पष्टता के लिए इसे छोड़ दिया। (बेशक आप इसके बजाय एन कॉलम के साथ एक-पंक्ति तालिका हो सकते हैं, लेकिन फिर प्रत्येक नए मूल्य को जोड़ने के लिए तालिका स्कीमा को अपडेट करने की आवश्यकता होती है, इसलिए उन्हें पार्स करने से जुड़ी जटिलता को दूर करने के लिए किसी अन्य जटिलता को शुरू करने की कीमत पर आता है)।
कोनराड मोरावस्की

टपल के बारे में अच्छी बात। वास्तव में, क्या (false, "foo")मतलब होगा?
कोनराड मोरावस्की

कम से कम अमरूद के विकल्प के साथ, एक अपवाद में परिणामों में एक शून्य डालने की कोशिश कर रहा है। आपको Optional.absent () का उपयोग करना होगा।
माइक पार्टरिज

@ माइकपार्ट्रिज अच्छी बात है। एक बदसूरत वर्कअराउंड नक्शा बदलने के लिए होगा Map<String, Optional<String>>और फिर आप के साथ समाप्त होगा Optional<Optional<String>>। एक कम भ्रामक समाधान अपने स्वयं के वैकल्पिक रोल करने की अनुमति देता है जो अनुमति देता है null, या एक समान बीजीय डेटा प्रकार है जो नापसंद करता है nullलेकिन इसमें 3 राज्य हैं - अनुपस्थित, अशक्त या वर्तमान। दोनों को लागू करना सरल है, हालांकि इसमें शामिल होने वाले बॉयलरप्लेट की मात्रा उस चीज के लिए अधिक है जो केवल आंतरिक रूप से उपयोग की जाएगी।
डोभाल

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

5

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

समस्या बिल्कुल यही है। लेकिन आपने पहले ही समाधान खुद पोस्ट कर दिया:

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

हालांकि, null या का उपयोग न करें Optional। आप कर सकते हैं और Optionalकेवल उपयोग करना चाहिए । आपकी "हैकिश" भावना के लिए, बस इसे नेस्टेड का उपयोग करें, इसलिए आप इसे समाप्त करते हैं, जिससे Optional<Optional<String>>यह स्पष्ट हो जाता है कि डेटाबेस में एक कुंजी हो सकती है (पहला विकल्प परत) और इसमें एक पूर्वनिर्धारित मान (दूसरा विकल्प परत) हो सकता है।

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

कृपया यह भी ध्यान दें कि आपके Optionalपास कुछ आराम कार्य हैं, ताकि आपको सारा काम स्वयं न करना पड़े। इसमें शामिल है:

  • static static <T> Optional<T> fromNullable(T nullableReference)अपने डेटाबेस इनपुट को Optionalप्रकारों में बदलने के लिए
  • abstract T or(T defaultValue) आंतरिक विकल्प परत के मुख्य मूल्य को प्राप्त करने के लिए या (यदि मौजूद नहीं है) अपना डिफ़ॉल्ट कुंजी मान प्राप्त करें

1
Optional<Optional<String>>बुराई दिखती है, हालाँकि इसमें कुछ आकर्षण है मुझे स्वीकार करना होगा
:)

क्या आप आगे बता सकते हैं कि यह बुराई क्यों लगती है? यह वास्तव में के रूप में एक ही पैटर्न है List<List<String>>। आप निश्चित रूप से (यदि भाषा अनुमति देता है) एक नया प्रकार बना सकते हैं जैसे DBConfigKeyकि लपेटता है Optional<Optional<String>>और यदि आप चाहें तो इसे अधिक पठनीय बनाते हैं।
वैलेंट्री

2
@valenterry यह बहुत अलग है। सूचियों की सूची कुछ प्रकार के डेटा को संग्रहीत करने का एक वैध तरीका है; वैकल्पिक का एक विकल्प डेटा के दो प्रकार की समस्याओं को इंगित करने का एक atypical तरीका है।
Ypnypn

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

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

5

मुझे पता है कि मुझे पार्टी में देर हो रही है, लेकिन वैसे भी आपके उपयोग का मामला जैसा दिखता है कि जावाProperties कैसे डिफ़ॉल्ट गुणों के एक सेट को परिभाषित करता है, जो कि उदाहरण के अनुसार लोड की गई कुंजी नहीं होने पर जाँच की जाएगी।

कार्यान्वयन के लिए Properties.getProperty(String)(जावा 7 से) को देखते हुए:

Object oval = super.get(key);
String sval = (oval instanceof String) ? (String)oval : null;
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;

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

एक समान, लेकिन थोड़ा और अधिक, @ Bћовић के उत्तर के लिए दृष्टिकोण भी हो सकता है:

public String getByKey(String key) {
    if (!valuesFromDatabase.containsKey(key)) {
        valuesFromDatabase.put(key, defaultValues.get(key));
    }
    return valuesFromDatabase.get(key);
}

4

हालाँकि मुझे लगता है कि @ Bћовић का जवाब ठीक है अगर मामले getValueByKeyमें कहीं और ज़रूरत है, तो मुझे नहीं लगता कि आपके कार्यक्रम के मामले में आपका समाधान खराब है, दोनों उपयोग के मामले हैं:

  • कुंजी के साथ स्वत: निर्माण के साथ कुंजी द्वारा पुनर्प्राप्ति पहले से मौजूद नहीं है और

  • उस स्वचालितता के बिना पुनर्प्राप्ति, डेटाबेस, भंडार या मुख्य नक्शे में कुछ भी बदलने के बिना ( getValueByKeyसार्वजनिक रूप से मधुमक्खी के बारे में सोचो , निजी नहीं)

यदि यह आपकी स्थिति है, और जब तक प्रदर्शन हिट स्वीकार्य है, मुझे लगता है कि आपका प्रस्तावित समाधान पूरी तरह से ठीक है। यह पुनर्प्राप्ति कोड के दोहराव से बचने का लाभ है, यह तीसरे पक्ष के ढांचे पर भरोसा नहीं करता है, और यह बहुत आसान है (कम से कम मेरी नजर में)।

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

बेशक, एक तीसरा विकल्प है: एक तीसरा, निजी तरीका बनाएं Tuple<Boolean, String>, जैसा कि आपने सुझाव दिया है, और इस पद्धति का पुन: उपयोग करें getValueByKeyऔर दोनों में getByKey। अधिक जटिल मामले के लिए, जो वास्तव में बेहतर विकल्प हो सकता है, लेकिन इस तरह के एक साधारण मामले के लिए जैसा कि यहां दिखाया गया है, इसमें IMHO की अधिकता की गंध है, और मुझे संदेह है कि कोड वास्तव में इस तरह से अधिक बनाए रखने योग्य हो जाता है। मैं कार्ल बेलेफ़ेल्ट द्वारा यहाँ सबसे ऊपरी उत्तर के साथ हूँ :

"आपको अपने कोड को सरल बनाने पर अपवादों का उपयोग करने के बारे में बुरा महसूस नहीं करना चाहिए"।


3

Optionalसही समाधान है। हालांकि, यदि आप पसंद करते हैं, तो एक विकल्प है जिसमें "दो नल" की भावना कम है, एक प्रहरी पर विचार करें।

keyNotFoundSentinelमान के साथ एक निजी स्थिर स्ट्रिंग को परिभाषित करें new String("")। *

अब निजी विधि के return keyNotFoundSentinelबजाय कर सकते हैं throw new KeyNotFoundException()। सार्वजनिक विधि उस मान के लिए जाँच कर सकती है

String rval = getValueByKey(key);
if (rval == keyNotFoundSentinel) { // reference equality, not string.equals
    ... // generate default value
} else {
    return rval;
}

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

* हम new String("")केवल ""स्ट्रिंग को "इंटर्न" करने से जावा को रोकने के बजाय जानबूझकर उपयोग करते हैं , जो इसे किसी अन्य खाली स्ट्रिंग के समान संदर्भ देगा। क्योंकि यह अतिरिक्त कदम था, हम गारंटी देते हैं कि स्ट्रिंग द्वारा निर्दिष्ट keyNotFoundSentinelएक अद्वितीय उदाहरण है, जिसे हमें यह सुनिश्चित करने की आवश्यकता है कि यह मानचित्र में कभी भी प्रकट नहीं हो सकता है।


यह, IMHO, सबसे अच्छा जवाब है।
fgp

2

जावा के सभी दर्द बिंदुओं से सीखी गई रूपरेखा से सीखें:

.NET इस समस्या से दो और अधिक सुंदर समाधान प्रदान करता है, इसके द्वारा उदाहरण:

बाद में जावा में लिखना बहुत आसान है, पूर्व में बस "मजबूत संदर्भ" सहायक वर्ग की आवश्यकता होती है।


Dictionaryपैटर्न के लिए एक सहसंयोजक-अनुकूल विकल्प होगा T TryGetValue(TKey, out bool)
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.