व्यावसायिक त्रुटियों से बचाने के लिए स्थैतिक प्रकार की जाँच का उपयोग करना


13

मैं स्थैतिक प्रकार की जाँच का बहुत बड़ा प्रशंसक हूँ। यह आपको इस तरह बेवकूफ बनाने से रोकता है:

// java code
Adult a = new Adult();
a.setAge("Roger"); //static type checker would complain
a.setName(42); //and here too

लेकिन यह आपको इस तरह बेवकूफ बनाने से नहीं रोकता है:

Adult a = new Adult();
// obviously you've mixed up these fields, but type checker won't complain
a.setAge(150); // nobody's ever lived this old
a.setWeight(42); // a 42lb adult would have serious health issues

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

class Age extends Integer{};
class Pounds extends Integer{};

class Adult{
    ...
    public void setAge(Age age){..}
    public void setWeight(Pounds pounds){...}
}

Adult a = new Adult();
a.setAge(new Age(42));
a.setWeight(new Pounds(150));

क्या यह अच्छा अभ्यास माना जाता है? या इस तरह के प्रतिबंधात्मक डिजाइन के साथ सड़क के नीचे अप्रत्याशित इंजीनियरिंग समस्याएं हैं?


5
a.SetAge( new Age(150) )अभी भी संकलन नहीं होगा ?
जॉन वू

1
जावा के इंट प्रकार की एक निश्चित सीमा होती है। स्पष्ट रूप से आप कस्टम रेंज के साथ पूर्णांक रखना चाहते हैं, उदाहरण के लिए पूर्णांक <18, 110>। आप परिष्कृत प्रकार या आश्रित प्रकार की तलाश कर रहे हैं, जो कुछ (गैर-मुख्यधारा) भाषाएं प्रदान करती हैं।
थियोडोरोस चटजिआनियाकिस

3
आप जिस बारे में बात कर रहे हैं वह डिजाइन करने का शानदार तरीका है! अफसोस की बात है, जावा में इतनी आदिम प्रकार की प्रणाली है कि यह सही करना मुश्किल है। और यहां तक ​​कि अगर आप इसे करने की कोशिश करते हैं, तो इसके परिणामस्वरूप कम प्रदर्शन या कम डेवलपर उत्पादकता जैसे दुष्प्रभाव हो सकते हैं।
यूफोरिक

@ जॉनोवू हाँ आपका उदाहरण अभी भी संकलित होगा, लेकिन यह उस तर्क के लिए विफलता का एकल बिंदु है। एक बार जब आप अपनी new Age(...)वस्तु की घोषणा कर देते हैं, तो आप इसे गलत तरीके Weightसे किसी अन्य स्थान पर चर के रूप में निर्दिष्ट नहीं कर सकते । यह उन स्थानों की संख्या को कम करता है जहां गलतियाँ हो सकती हैं।
J-bob

जवाबों:


12

आप अनिवार्य रूप से एक इकाई प्रणाली (नहीं, इकाई परीक्षण नहीं, "इकाई" के रूप में "भौतिक इकाई", जैसे मीटर, वोल्ट आदि) के लिए पूछ रहे हैं।

आपके कोड में Ageसमय का प्रतिनिधित्व करता है और Poundsद्रव्यमान का प्रतिनिधित्व करता है। इससे यूनिट रूपांतरण, आधार इकाइयों, परिशुद्धता, आदि जैसी चीजें होती हैं।


उदाहरण के लिए, जावा में ऐसी चीज़ प्राप्त करने का प्रयास किया गया है:

बाद के दो इस जीथब चीज़ में रहते हैं: https://github.com/unitsofmeasurement


C ++ में Boost के माध्यम से इकाइयाँ हैं


LabView इकाइयों के एक समूह के साथ आता है ।


अन्य भाषाओं में अन्य उदाहरण हैं। (संपादन का स्वागत है)


क्या यह अच्छा अभ्यास माना जाता है?

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

लेकिन किसी भी सामान्य उद्देश्य में उच्च स्तर की भाषा, जहां इस तरह की कठोरता के लिए मांग कम है, यह संभवतः अप्रत्याशित है।

या इस तरह के प्रतिबंधात्मक डिजाइन के साथ सड़क के नीचे अप्रत्याशित इंजीनियरिंग समस्याएं हैं?

मेरा अनुमान होगा: प्रदर्शन / स्मृति। यदि आप बहुत सारे मूल्यों से निपटते हैं, तो प्रति मूल्य की वस्तु का ओवरहेड एक समस्या बन सकता है। लेकिन हमेशा की तरह: समयपूर्व अनुकूलन सभी बुराई की जड़ है

मुझे लगता है कि बड़ी "समस्या" लोगों को इसकी आदत हो रही है, क्योंकि इकाई आमतौर पर स्पष्ट रूप से इस तरह परिभाषित होती है:

class Adult
{
    ...
    public void setAge(int ageInYears){..}

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


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

1
मुझे लगता है कि कस्टम श्रेणियां इसे इकाइयों के पुस्तकालय के दायरे से बाहर और आश्रित प्रकारों में स्थानांतरित करती हैं
jk।

6

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

यदि आपको इकाई के लिए एक प्रकार को परिभाषित करने वाले माप के अधिक दानेदार स्तर की आवश्यकता है, तो यह फायदेमंद है:

public struct Weight {
    private int pounds;
    private int ounces;

    public Weight(int pounds, int ounces) {
        // Value range checks go here
        // Throw exception if ounces is greater than 16?
    }

    // Getters go here
}

"उम्र" जैसी किसी चीज़ के लिए मैं उस व्यक्ति की जन्मतिथि के आधार पर रन टाइम पर गणना करने की सलाह देता हूं:

public class Adult {
    private Date birthDate;

    public Interval getCurrentAge() {
        return calculateAge(Date.now());
    }

    public Interval calculateAge(Date date) {
        // Return interval between birthDate and date
    }
}

2

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

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

सत्यापन, उदाहरण के लिए जाँच कर रहा है कि किसी व्यक्ति की ऊँचाई "उचित" एक और मुद्दा है। आप ऐसे कोड को अपनी Adultकक्षा (कंस्ट्रक्टर या सेटर), या अपने टैग किए गए प्रकार / आवरण कक्षाओं के अंदर रख सकते हैं। एक तरह से, अंतर्निहित कक्षाएं जैसे कि URLया UUIDऐसी भूमिका को पूरा करना (दूसरों के बीच, उदाहरण के लिए उपयोगिता के तरीके प्रदान करना)।

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

मेरे द्वारा लिखे गए कोड में, मैं अक्सर रैपर कक्षाएं बनाता हूं यदि मैं मानचित्रों के आसपास से गुजरता हूं। इस तरह के रूप Map<String, String>में खुद के द्वारा बहुत अपारदर्शी हैं, इसलिए उन्हें सार्थक नामों के साथ कक्षाओं में लपेटना NameToAddressबहुत मदद करता है। बेशक, टैग किए गए प्रकारों के साथ, आप लिख सकते हैं Map<Name, Address>और पूरे नक्शे के लिए आवरण की आवश्यकता नहीं है।

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

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