यदि आप 'अंतिम' कीवर्ड के बिना 'स्थिर' कीवर्ड का उपयोग कर रहे हैं, तो यह आपके डिज़ाइन पर सावधानीपूर्वक विचार करने के लिए एक संकेत होना चाहिए। यहां तक कि एक 'अंतिम' की उपस्थिति भी एक नि: शुल्क पास नहीं है, क्योंकि एक उत्परिवर्ती स्थिर अंतिम वस्तु सिर्फ खतरनाक हो सकती है।
मैं अनुमान लगाता हूं कि जब मैं, फाइनल ’के बिना the स्टैटिक’ देखता हूं, तो यह लगभग 85% होता है, यह गलत है। अक्सर, मैं इन समस्याओं को मास्क करने या छिपाने के लिए अजीबोगरीब वर्कआउट करूंगा।
कृपया स्थैतिक उत्परिवर्तन न बनाएं। खासकर कलेक्शन। सामान्य तौर पर, संग्रह को तब आरंभीकृत किया जाना चाहिए जब उनकी युक्त वस्तु को आरंभीकृत किया गया हो और उन्हें डिज़ाइन किया जाना चाहिए ताकि जब उनकी वस्तु को भुला दिया जाए तो वे रीसेट या भूल जाएं।
स्टैटिक्स का उपयोग करने से बहुत सूक्ष्म कीड़े पैदा हो सकते हैं जो दर्द के इंजीनियरों दिनों को बनाए रखेंगे। मुझे पता है, क्योंकि मैंने इन दोनों कीड़ों को बनाया और उनका शिकार किया है।
यदि आप अधिक जानकारी चाहते हैं, तो कृपया पढ़ें ...
क्यों नहीं स्टैटिक्स का उपयोग करें?
स्टैटिक्स के साथ कई मुद्दे हैं, जिसमें लेखन और निष्पादन परीक्षण, साथ ही सूक्ष्म कीड़े शामिल हैं जो तुरंत स्पष्ट नहीं हैं।
स्थिर वस्तुओं पर निर्भर कोड आसानी से परीक्षण की गई इकाई नहीं हो सकता है, और स्टैटिक्स को आसानी से (आमतौर पर) मज़ाक नहीं किया जा सकता है।
यदि आप स्टैटिक्स का उपयोग करते हैं, तो उच्च स्तर के घटकों का परीक्षण करने के लिए कक्षा के कार्यान्वयन को स्वैप करना संभव नहीं है। उदाहरण के लिए, एक स्थैतिक CustomerDAO की कल्पना करें जो ग्राहक की वस्तुओं को डेटाबेस से लोड करता है। अब मेरे पास एक वर्ग CustomerFilter है, जिसे कुछ ग्राहक वस्तुओं तक पहुंचने की आवश्यकता है। अगर CustomerDAO स्थिर है, तो मैं अपने डेटाबेस को पहले शुरू करने और उपयोगी जानकारी के बिना ग्राहकफ़िल्टर के लिए एक परीक्षण नहीं लिख सकता।
और डेटाबेस की आबादी और आरंभीकरण में लंबा समय लगता है। और मेरे अनुभव में, आपका डीबी इनिशियलाइज़ेशन फ्रेमवर्क समय के साथ बदल जाएगा, जिसका अर्थ है कि डेटा मॉर्फ होगा, और परीक्षण टूट सकते हैं। IE, कल्पना करें कि ग्राहक 1 एक वीआईपी हुआ करता था, लेकिन DB आरंभीकरण ढांचा बदल गया, और अब ग्राहक 1 अब VIP नहीं है, लेकिन आपका परीक्षण ग्राहक 1 को लोड करने के लिए कठिन-कोडित किया गया था ...
एक बेहतर तरीका यह है कि एक CustomerDAO को तत्काल भेजा जाए, और जब इसका निर्माण हो जाए, तो इसे CustomerFilter में पास कर दें। (स्प्रिंग का उपयोग करने के लिए एक बेहतर तरीका यह होगा कि कंट्रोल फ्रेमवर्क का दूसरा उलटा उपयोग किया जाए।
एक बार जब आप ऐसा कर लेते हैं, तो आप अपने CustomerFilterTest में एक वैकल्पिक DAO को जल्दी से मॉक या स्टब कर सकते हैं, जिससे आपको परीक्षण पर अधिक नियंत्रण रखने की अनुमति मिलती है,
स्टैटिक डीएओ के बिना, परीक्षण तेज होगा (डीबी आरंभीकरण नहीं) और अधिक विश्वसनीय (क्योंकि यह डीबी आरंभीकरण कोड बदलने पर विफल नहीं होगा)। उदाहरण के लिए, इस मामले में ग्राहक 1 सुनिश्चित करना और हमेशा एक वीआईपी होगा, जहां तक परीक्षण का संबंध है।
परीक्षाएँ छूटती हैं
स्टैटिक्स एक वास्तविक समस्या का कारण बनते हैं जब यूनिट परीक्षणों के एक साथ सूट करते हैं (उदाहरण के लिए, आपके कॉन्टीन्यूअस इंटीग्रेशन सर्वर के साथ)। नेटवर्क सॉकेट ऑब्जेक्ट के स्थैतिक मानचित्र की कल्पना करें जो एक परीक्षण से दूसरे में खुला रहता है। पहला परीक्षण पोर्ट 8080 पर एक सॉकेट खोल सकता है, लेकिन परीक्षण के खराब होने पर आप मैप को खाली करना भूल गए। अब जब दूसरा परीक्षण शुरू होता है, तो यह पोर्ट 8080 के लिए एक नया सॉकेट बनाने की कोशिश करते समय दुर्घटनाग्रस्त होने की संभावना है, क्योंकि बंदरगाह अभी भी कब्जा है। यह भी कल्पना करें कि आपके स्थैतिक संग्रह में सॉकेट संदर्भ हटाए नहीं गए हैं, और (WeakHashMap के अपवाद के साथ) कचरा एकत्र करने के योग्य नहीं हैं, जिससे मेमोरी रिसाव हो सकता है।
यह एक सामान्यीकृत उदाहरण है, लेकिन बड़ी प्रणालियों में, यह समस्या ALL TIME होती है। लोग एक ही JVM में अपने सॉफ़्टवेयर को बार-बार शुरू करने और रोकने के लिए इकाई परीक्षणों के बारे में नहीं सोचते हैं, लेकिन यह आपके सॉफ़्टवेयर डिज़ाइन का एक अच्छा परीक्षण है, और यदि आपके पास उच्च उपलब्धता के लिए आकांक्षाएं हैं, तो यह कुछ ऐसा है जिसके बारे में आपको जानकारी होनी चाहिए।
ये समस्याएं अक्सर फ्रेमवर्क ऑब्जेक्ट्स के साथ उत्पन्न होती हैं, उदाहरण के लिए, आपका DB एक्सेस, कैशिंग, मैसेजिंग और लॉगिंग लेयर्स। यदि आप जावा ईई या कुछ सर्वोत्तम नस्ल के फ्रेमवर्क का उपयोग कर रहे हैं, तो वे संभवतः आपके लिए इसका बहुत प्रबंधन करते हैं, लेकिन अगर मेरी तरह आप एक विरासत प्रणाली के साथ काम कर रहे हैं, तो आपके पास इन परतों तक पहुंचने के लिए बहुत सारे कस्टम फ्रेमवर्क हो सकते हैं।
यदि सिस्टम कॉन्फ़िगरेशन जो इन फ्रेमवर्क घटकों पर लागू होता है, यूनिट परीक्षणों के बीच बदल जाता है, और यूनिट टेस्ट फ्रेमवर्क फाड़ नहीं देता है और घटकों का पुनर्निर्माण नहीं करता है, तो ये परिवर्तन प्रभावी नहीं हो सकते हैं, और जब कोई परीक्षण उन परिवर्तनों पर निर्भर करता है, तो वे विफल हो जाएंगे। ।
यहां तक कि गैर-फ्रेमवर्क घटक भी इस समस्या के अधीन हैं। OpenOrders नामक एक स्थिर मानचित्र की कल्पना करें। आप एक परीक्षण लिखते हैं जो कुछ खुले आदेश बनाता है, और यह सुनिश्चित करने के लिए जांच करता है कि वे सभी सही स्थिति में हैं, फिर परीक्षण समाप्त होता है। एक अन्य डेवलपर एक दूसरा परीक्षण लिखता है जो ओपनऑर्डर्स के नक्शे में इसकी ज़रूरतों को पूरा करता है, फिर आदेशों की संख्या सटीक है। व्यक्तिगत रूप से चलाएं, ये परीक्षण दोनों पास होंगे, लेकिन जब एक सूट में एक साथ दौड़ेंगे, तो वे विफल हो जाएंगे।
इससे भी बदतर, विफलता उस क्रम पर आधारित हो सकती है जिसमें परीक्षण चलाए गए थे।
इस मामले में, स्टैटिक्स से बचकर, आप परीक्षण उदाहरणों में डेटा को बनाए रखने के जोखिम से बचते हैं, बेहतर परीक्षण विश्वसनीयता सुनिश्चित करते हैं।
सूक्ष्म कीड़े
यदि आप उच्च उपलब्धता वाले वातावरण में काम करते हैं, या कहीं भी थ्रेड शुरू और बंद किए जा सकते हैं, तो यूनिट टेस्ट सूट के साथ उपरोक्त चिंता तब लागू हो सकती है जब आपका कोड उत्पादन पर भी चल रहा हो।
थ्रेड्स के साथ काम करते समय, डेटा को स्टोर करने के लिए एक स्थिर ऑब्जेक्ट का उपयोग करने के बजाय, थ्रेड के स्टार्टअप चरण के दौरान आरम्भ की गई ऑब्जेक्ट का उपयोग करना बेहतर होता है। इस तरह, हर बार जब थ्रेड शुरू किया जाता है, तो ऑब्जेक्ट का एक नया उदाहरण (संभावित नए कॉन्फ़िगरेशन के साथ) बनाया जाता है, और आप थ्रेड ब्लीडिंग के एक उदाहरण से अगले उदाहरण तक डेटा से बचते हैं।
जब एक धागा मर जाता है, तो एक स्थिर वस्तु को रीसेट या कचरा एकत्र नहीं किया जाता है। कल्पना कीजिए कि आपके पास "EmailCustomers" नामक एक धागा है, और जब यह शुरू होता है तो यह ईमेल पतों की एक सूची के साथ एक स्थिर स्ट्रिंग संग्रह को पॉप्युलेट करता है, फिर प्रत्येक पते को ईमेल करना शुरू करता है। मान लें कि थ्रेड बाधित हो गया है या किसी तरह रद्द कर दिया गया है, इसलिए आपका उच्च उपलब्धता ढांचा थ्रेड को पुनरारंभ करता है। फिर जब धागा शुरू होता है, तो यह ग्राहकों की सूची को फिर से लोड करता है। लेकिन क्योंकि संग्रह स्थिर है, यह पिछले संग्रह से ईमेल पते की सूची को बनाए रख सकता है। अब कुछ ग्राहकों को डुप्लिकेट ईमेल मिल सकते हैं।
एक पहलू: स्टेटिक फाइनल
"स्टैटिक फ़ाइनल" का उपयोग प्रभावी रूप से C #define के जावा समतुल्य है, हालाँकि तकनीकी कार्यान्वयन अंतर हैं। संकलन से पहले AC / C ++ #define को प्री-प्रोसेसर द्वारा कोड से स्वैप किया जाता है। एक जावा "स्टैटिक फाइनल" स्टैक पर मेमोरी रेजिडेंट को समाप्त कर देगा। इस तरह, यह C # में "स्थिर कॉन्स्टेबल" वैरिएबल से अधिक है, जितना कि यह #define पर है।
सारांश
मुझे उम्मीद है कि यह कुछ बुनियादी कारणों की व्याख्या करने में मदद करता है कि स्टैटिक्स समस्याग्रस्त क्यों हैं। यदि आप जावा EE या स्प्रिंग इत्यादि जैसे आधुनिक जावा फ्रेमवर्क का उपयोग कर रहे हैं, तो हो सकता है कि आप इनमें से कई स्थितियों का सामना न करें, लेकिन यदि आप विरासत कोड के एक बड़े निकाय के साथ काम कर रहे हैं, तो वे बहुत अधिक बन सकते हैं।