मैं यह पाने में असमर्थ हूं कि वे कौन से परिदृश्य हैं जहां हमें एक अपरिवर्तनीय वर्ग की आवश्यकता है।
क्या आपने कभी ऐसी किसी आवश्यकता का सामना किया है? या क्या आप हमें कोई वास्तविक उदाहरण दे सकते हैं जहां हमें इस पैटर्न का उपयोग करना चाहिए।
मैं यह पाने में असमर्थ हूं कि वे कौन से परिदृश्य हैं जहां हमें एक अपरिवर्तनीय वर्ग की आवश्यकता है।
क्या आपने कभी ऐसी किसी आवश्यकता का सामना किया है? या क्या आप हमें कोई वास्तविक उदाहरण दे सकते हैं जहां हमें इस पैटर्न का उपयोग करना चाहिए।
जवाबों:
अन्य उत्तर यह समझाने पर भी केंद्रित हैं कि अपरिवर्तनशीलता क्यों अच्छी है। यह बहुत अच्छा है और जब भी संभव हो मैं इसका उपयोग करता हूं। हालाँकि, यह आपका सवाल नहीं है । मैं यह सुनिश्चित करने की कोशिश करने के लिए आपके प्रश्न बिंदु को ले जाऊंगा कि आपको उत्तर और उदाहरण मिल रहे हैं।
मैं यह पाने में असमर्थ हूं कि वे कौन से परिदृश्य हैं जहां हमें एक अपरिवर्तनीय वर्ग की आवश्यकता है।
"नीड" यहाँ एक सापेक्ष शब्द है। अपरिवर्तनीय कक्षाएं एक डिज़ाइन पैटर्न हैं जो किसी भी प्रतिमान / पैटर्न / उपकरण की तरह है, निर्माण सॉफ्टवेयर को आसान बनाने के लिए है। इसी तरह, OO प्रतिमान के साथ आने से पहले बहुत सारे कोड लिखे गए थे, लेकिन मुझे उन प्रोग्रामर्स में गिना गया जिन्हें " OO " की आवश्यकता थी । OO जैसे अपरिवर्तनीय वर्गों की सख्त जरूरत नहीं है , लेकिन मुझे उनकी तरह काम करने की जरूरत है।
क्या आपने कभी ऐसी किसी आवश्यकता का सामना किया है?
यदि आप समस्या के क्षेत्र में वस्तुओं को सही दृष्टिकोण से नहीं देख रहे हैं, तो आपको एक अपरिवर्तनीय वस्तु की आवश्यकता नहीं दिख सकती है । यह सोचना आसान हो सकता है कि एक समस्या डोमेन को किसी अपरिवर्तनीय वर्ग की आवश्यकता नहीं है यदि आप परिचित नहीं हैं, तो उन्हें लाभप्रद रूप से उपयोग करने के लिए कब जाना चाहिए।
मैं अक्सर अपरिवर्तनीय कक्षाओं का उपयोग करता हूं, जहां मैं अपने समस्या डोमेन में दिए गए ऑब्जेक्ट को एक मूल्य या निश्चित उदाहरण के रूप में सोचता हूं । यह धारणा कभी-कभी परिप्रेक्ष्य या दृष्टिकोण पर निर्भर होती है, लेकिन आदर्श रूप से, अच्छे उम्मीदवार वस्तुओं की पहचान करने के लिए सही परिप्रेक्ष्य में स्विच करना आसान होगा।
आप एक बेहतर समझ प्राप्त कर सकते हैं कि अपरिवर्तनीय वस्तुएं वास्तव में उपयोगी हैं (यदि कड़ाई से आवश्यक नहीं), तो सुनिश्चित करें कि आपने विभिन्न पुस्तकों / ऑनलाइन लेखों को पढ़ने के लिए यह सुनिश्चित करने के लिए कि अपरिवर्तनीय कक्षाओं के बारे में कैसे सोचा जाए। आपको शुरू करने के लिए एक अच्छा लेख जावा सिद्धांत और अभ्यास है: उत्परिवर्तित करने के लिए या नहीं करने के लिए?
मैं नीचे दिए गए उदाहरणों की एक जोड़ी देने की कोशिश करूँगा कि कैसे विभिन्न परिप्रेक्ष्य में वस्तुओं को देख सकते हैं (जो परस्पर बनाम अपरिवर्तनीय हैं) स्पष्ट करने के लिए कि मैं परिप्रेक्ष्य से क्या मतलब है।
... क्या आप हमें कोई वास्तविक उदाहरण दे सकते हैं जहां हमें इस पैटर्न का उपयोग करना चाहिए।
चूंकि आपने वास्तविक उदाहरणों के लिए कहा था कि मैं आपको कुछ देता हूं, लेकिन पहले, आइए कुछ क्लासिक उदाहरणों के साथ शुरू करते हैं।
क्लासिक मान ऑब्जेक्ट
स्ट्रिंग्स और पूर्णांकों को अक्सर मूल्यों के रूप में सोचा जाता है। इसलिए यह आश्चर्य की बात नहीं है कि जावा में स्ट्रिंग क्लास और इंटेगर रैपर क्लास (साथ ही अन्य रैपर क्लास) अपरिवर्तनीय हैं। एक रंग को आमतौर पर मूल्य के रूप में माना जाता है, इस प्रकार अपरिवर्तनीय रंग वर्ग।
counterexample
इसके विपरीत, एक कार को आमतौर पर मूल्य वस्तु के रूप में नहीं सोचा जाता है। कार की मॉडलिंग का मतलब आमतौर पर एक ऐसी क्लास बनाना होता है जिसमें बदलती अवस्था (ओडोमीटर, स्पीड, फ्यूल लेवल आदि) हो। हालांकि, कुछ डोमेन हैं जहां यह कार एक मूल्य वस्तु हो सकती है। उदाहरण के लिए, एक कार (या विशेष रूप से एक कार मॉडल) को किसी दिए गए वाहन के लिए उचित मोटर तेल देखने के लिए एक ऐप में एक मूल्य वस्तु के रूप में सोचा जा सकता है।
ताश के पत्ते
कभी प्लेइंग कार्ड प्रोग्राम लिखिए? मैंने किया। मैं एक म्यूटेबल सूट और रैंक के साथ एक म्यूटेबल ऑब्जेक्ट के रूप में एक प्लेइंग कार्ड का प्रतिनिधित्व कर सकता था। एक ड्रॉ-पोकर हाथ 5 निश्चित उदाहरण हो सकते हैं जहां मेरे हाथ में 5 वें कार्ड की जगह का मतलब होगा कि सूट और रैंक आइवर को बदलकर 5 वें प्लेइंग कार्ड उदाहरण को नए कार्ड में बदल दिया जाए।
हालाँकि, मैं एक प्लेइंग कार्ड को एक अपरिवर्तनीय वस्तु के रूप में देखता हूं जिसमें एक बार अपरिवर्तित सूट और रैंक होता है। मेरा ड्रॉ पोकर हैंड 5 इंस्टेंसेस होगा और मेरे हाथ में एक कार्ड की जगह उन इंस्टेंस में से एक को छोड़ना होगा और मेरे हाथ में एक नया रैंडम इंस्टेंस जोड़ना होगा।
नक्शा प्रोजेक्शन
एक अंतिम उदाहरण है जब मैंने कुछ मानचित्र कोड पर काम किया था जहाँ मानचित्र विभिन्न अनुमानों में खुद को प्रदर्शित कर सकता था । मूल कोड में मानचित्र का एक निश्चित, लेकिन उत्परिवर्तित प्रक्षेपण उदाहरण (ऊपर के परिवर्तनशील प्लेइंग कार्ड की तरह) का उपयोग किया गया था। मानचित्र प्रक्षेपण को बदलने का अर्थ था मानचित्र के प्रक्षेपण उदाहरण के आइवर (प्रक्षेपण प्रकार, केंद्र बिंदु, ज़ूम, आदि) को बदलना।
हालांकि, मुझे लगा कि अगर मैं एक अचल मूल्य या निश्चित उदाहरण के रूप में प्रक्षेपण के बारे में सोचता हूं तो डिजाइन सरल था। मानचित्र प्रक्षेपण को बदलने का मतलब था कि मानचित्र के निश्चित प्रक्षेपण उदाहरण को बदलने के बजाय मानचित्र के संदर्भ में एक अलग प्रक्षेपण उदाहरण है। इसने नामांकित अनुमानों को कैप्चर करना भी आसान बना दिया MERCATOR_WORLD_VIEW
।
अपरिवर्तनीय कक्षाएं सामान्य रूप से डिजाइन, कार्यान्वयन और सही तरीके से उपयोग करने के लिए बहुत सरल हैं । एक उदाहरण स्ट्रिंग है: इसका कार्यान्वयन C ++ java.lang.String
की तुलना में काफी सरल है std::string
, ज्यादातर इसकी अपरिवर्तनीयता के कारण।
एक विशेष क्षेत्र जहां अपरिवर्तनीयता एक विशेष रूप से बड़ा अंतर है, संगामिति है: अपरिवर्तनीय वस्तुओं को कई थ्रेड्स के बीच सुरक्षित रूप से साझा किया जा सकता है , जबकि परिवर्तनशील वस्तुओं को सावधानीपूर्वक डिजाइन और कार्यान्वयन के माध्यम से थ्रेड-सुरक्षित बनाया जाना चाहिए - आमतौर पर यह एक तुच्छ कार्य से बहुत दूर है।
अपडेट: प्रभावी जावा 2 संस्करण इस मुद्दे से विस्तार से निपटता है - देखें आइटम 15: उत्परिवर्तन को कम करें ।
ये संबंधित पोस्ट भी देखें:
जोशुआ बलोच द्वारा प्रभावी जावा अपरिवर्तनीय कक्षाएं लिखने के कई कारणों की रूपरेखा देता है:
सामान्य तौर पर किसी वस्तु को अपरिवर्तनीय बनाना अच्छा होता है जब तक कि उसके परिणामस्वरूप गंभीर प्रदर्शन समस्याएं न हों। ऐसी परिस्थितियों में, उत्परिवर्ती बिल्डर वस्तुओं का उपयोग अपरिवर्तनीय वस्तुओं जैसे StringBuilder का निर्माण करने के लिए किया जा सकता है
हश्मप एक उत्कृष्ट उदाहरण हैं। यह जरूरी है कि मानचित्र की कुंजी अपरिवर्तनीय हो। यदि कुंजी अपरिवर्तनीय नहीं है, और आप कुंजी पर एक मान बदलते हैं जैसे कि हैशकोड () के परिणामस्वरूप नया मान होगा, तो मानचित्र अब टूट गया है (हैश तालिका में एक गलत स्थान अब कुंजी है।)
जावा व्यावहारिक रूप से एक और सभी संदर्भ है। कभी-कभी एक उदाहरण को कई बार संदर्भित किया जाता है। यदि आप इस तरह के उदाहरण को बदलते हैं, तो यह उसके सभी संदर्भों में परिलक्षित होगा। कभी-कभी आप केवल यह नहीं चाहते हैं कि मजबूती और थ्रेडसैफ़िटी में सुधार हो। तब एक अपरिवर्तनीय वर्ग उपयोगी होता है ताकि एक नया उदाहरण बनाने के लिए मजबूर किया जाए और इसे वर्तमान संदर्भ में पुन: असाइन किया जाए। इस तरह अन्य संदर्भों का मूल उदाहरण अछूता रह जाता है।
कल्पना कीजिए कि जावा कैसा दिखेगा String
पारस्परिक ।
Date
और Calendar
परस्पर थे। ओह, रुको, वे हैं, ओह SH
String
में परिवर्तन योग्य है! (संकेत: कुछ पुराने JRockit संस्करण)। String.trim () कॉल करने के परिणामस्वरूप मूल स्ट्रिंग को ट्रिम किया गया
हमें प्रति वर्ग से अपरिवर्तनीय वर्गों की आवश्यकता नहीं है, लेकिन वे निश्चित रूप से कुछ प्रोग्रामिंग कार्यों को आसान बना सकते हैं, खासकर जब कई धागे शामिल होते हैं। आपको किसी अपरिवर्तनीय वस्तु तक पहुँचने के लिए कोई ताला लगाने की ज़रूरत नहीं है, और इस तरह की वस्तु के बारे में आपने जो भी तथ्य स्थापित किए हैं, वे भविष्य में भी सही रहेंगे।
चलो एक चरम मामला लेते हैं: पूर्णांक स्थिरांक। यदि मैं "x = x + 1" जैसा कोई वक्तव्य लिखता हूं, तो मैं 100% विश्वासपात्र होना चाहता हूं कि संख्या "1" किसी तरह 2 नहीं बनेगी, चाहे वह कार्यक्रम में कहीं भी हो।
अब ठीक है, पूर्णांक स्थिरांक एक वर्ग नहीं हैं, लेकिन अवधारणा समान है। मान लीजिए मैं लिखता हूं:
String customerId=getCustomerId();
String customerName=getCustomerName(customerId);
String customerBalance=getCustomerBalance(customerid);
काफी सरल लगता है। लेकिन अगर स्ट्रिंग्स अपरिवर्तनीय नहीं थे, तो मुझे इस संभावना पर विचार करना होगा कि getCustomerName customerId को बदल सकता है, ताकि जब मैं getCustomerBalance कहूं, तो मुझे एक अलग ग्राहक के लिए शेष राशि मिल रही है। अब आप कह सकते हैं, "दुनिया में कोई भी क्यों एक getCustomerName फ़ंक्शन लिख रहा है, जिससे यह आईडी बदल जाएगा? इससे कोई मतलब नहीं होगा।" लेकिन यह ठीक वही है जहाँ आप मुसीबत में पड़ सकते हैं। उपरोक्त कोड लिखने वाले व्यक्ति को यह स्पष्ट हो सकता है कि फ़ंक्शन पैरामीटर को नहीं बदलेगा। फिर कोई ऐसा व्यक्ति आता है जिसे उस फ़ंक्शन के एक अन्य उपयोग को संशोधित करना होता है, जहां उस मामले को संभालने के लिए जहां एक ग्राहक के एक ही नाम के तहत कई खाते हैं। और वह कहता है, "ओह, यहाँ यह आसान काम है नाम का फ़ंक्शन है जो पहले से ही नाम देख रहा है। मैं।"
अपरिवर्तनीयता का सीधा मतलब है कि वस्तुओं का एक निश्चित वर्ग स्थिर है, और हम उन्हें स्थिरांक के रूप में मान सकते हैं।
(बेशक उपयोगकर्ता एक भिन्न "स्थिर वस्तु" को एक चर में निर्दिष्ट कर सकता है। कोई व्यक्ति स्ट्रिंग s = "हैलो" लिख सकता है, और फिर बाद में s = "अलविदा" लिख सकता है; जब तक कि मैं चर को अंतिम नहीं बना देता, मुझे यकीन नहीं हो सकता है; यह मेरे कोड के अपने ब्लॉक के भीतर नहीं बदला जा रहा है। जैसे ही पूर्णांक कॉन्स्टेंट मुझे आश्वस्त करते हैं कि "1" हमेशा एक ही नंबर होता है, लेकिन ऐसा नहीं है कि "x = 1" को "x = 2" लिखकर कभी नहीं बदला जाएगा। लेकिन मैं विश्वासपात्र हो सकता है कि अगर मेरे पास एक अपरिवर्तनीय वस्तु के लिए एक हैंडल है, तो कोई भी फ़ंक्शन जो मैं इसे पास करता हूं वह इसे मुझ पर बदलने के लिए कर सकता है, या यह कि अगर मैं इसकी दो प्रतियां बनाता हूं, तो एक प्रतिलिपि रखने वाले चर में कोई परिवर्तन नहीं होगा। अन्य आदि।
अपरिवर्तनीयता के विभिन्न कारण हैं:
String
वर्ग।इसलिए, यदि आप एक नेटवर्क सेवा के माध्यम से डेटा भेजना चाहते हैं, और आप इस बात की गारंटी चाहते हैं कि आपके पास आपका परिणाम वही होगा जो आपने भेजा था, तो इसे अपरिवर्तनीय के रूप में सेट करें।
final
जावा में ध्वजांकित सभी कक्षाएं अपरिवर्तनीय नहीं हैं, और सभी अपरिवर्तनीय वर्ग ध्वजांकित नहीं हैं final
।
मैं एक अलग दृष्टिकोण से इस पर हमला करने जा रहा हूं। मुझे लगता है कि अपरिवर्तनीय वस्तुएं कोड पढ़ने के दौरान मेरे लिए जीवन को आसान बनाती हैं।
यदि मेरे पास एक परिवर्तनशील वस्तु है, तो मुझे यकीन नहीं है कि इसका मूल्य क्या है अगर यह कभी भी मेरे तत्काल दायरे के बाहर उपयोग किया जाता है। मान लीजिए कि मैं MyMutableObject
एक विधि के स्थानीय चरों में बनाता हूं , इसे मानों के साथ भरें, फिर इसे पांच अन्य तरीकों से पास करें। उन तरीकों में से कोई भी मेरी वस्तु की स्थिति को बदल सकता है, इसलिए दो चीजों में से एक को घटित करना होगा:
पहले मेरे कोड के बारे में तर्क करना मुश्किल बनाता है। दूसरा मेरे कोड को प्रदर्शन में बेकार कर देता है - मैं मूल रूप से कॉपी-ऑन-राइट शब्दार्थ के साथ एक अपरिवर्तनीय वस्तु की नकल कर रहा हूं, लेकिन यह हर समय कर रहा है कि क्या या नहीं कहा जाता है कि क्या वास्तव में मेरी वस्तु की स्थिति को संशोधित करता है।
यदि मैं इसके बजाय उपयोग करता MyImmutableObject
हूं, तो मुझे आश्वासन दिया जा सकता है कि मैंने जो सेट किया है वह मेरी पद्धति के जीवन के लिए मूल्य क्या होगा। "कोई दूरी पर कोई डरावना कार्रवाई" नहीं है जो इसे मेरे नीचे से बदल देगा और पाँच अन्य तरीकों को लागू करने से पहले मुझे अपनी वस्तु की रक्षात्मक प्रतियां बनाने की कोई आवश्यकता नहीं है। यदि अन्य विधियां अपने उद्देश्यों के लिए चीजों को बदलना चाहती हैं, तो उन्हें प्रतिलिपि बनाना होगा - लेकिन वे केवल ऐसा करते हैं यदि उन्हें वास्तव में एक प्रति बनानी होती है (जैसा कि प्रत्येक और प्रत्येक बाहरी विधि कॉल करने से पहले मेरे द्वारा किया गया है)। मैं अपने आप को उन तरीकों पर नज़र रखने के मानसिक संसाधनों से अलग करता हूं जो शायद मेरे वर्तमान स्रोत फ़ाइल में भी नहीं हो सकते हैं, और मैं सिस्टम को केवल मामले में अनावश्यक रक्षात्मक प्रतियां बनाने के ओवरहेड को छोड़ देता हूं।
(यदि मैं जावा दुनिया से बाहर जाता हूं और कहता हूं, सी ++ दुनिया, दूसरों के बीच में, मैं भी पेचीदा हो सकता हूं। मैं वस्तुओं को प्रकट कर सकता हूं जैसे कि वे परस्पर हैं, लेकिन पर्दे के पीछे उन्हें पारदर्शी रूप से किसी पर भी क्लोन बनाते हैं। राज्य परिवर्तन की तरह - यह कॉपी-ऑन-राइट है - जिसमें कोई भी समझदार नहीं है।)
भविष्य के आगंतुकों के लिए मेरे 2 सेंट:
2 परिदृश्य जहां अपरिवर्तनीय वस्तुएँ अच्छे विकल्प हैं:
मल्टी-थ्रेडेड वातावरण में कॉनएरेबिलिटी मुद्दे बहुत अच्छी तरह से सिंक्रोनाइज़ेशन द्वारा हल किए जा सकते हैं, लेकिन सिंक्रोनाइज़ेशन महंगा मामला है ("क्यों" पर यहां खुदाई नहीं होगी), इसलिए यदि आप अपरिवर्तनीय वस्तुओं का उपयोग कर रहे हैं, तो समसामयिक समस्या को हल करने के लिए कोई सिंक्रनाइज़ेशन नहीं है क्योंकि राज्य अपरिवर्तनीय वस्तुओं को नहीं बदला जा सकता है, और यदि राज्य को नहीं बदला जा सकता है, तो सभी थ्रेड ऑब्जेक्ट को सहज रूप से एक्सेस कर सकते हैं। इसलिए, अपरिवर्तनीय वस्तुएँ बहु-थ्रेडेड वातावरण में साझा किए गए ऑब्जेक्ट के लिए एक बढ़िया विकल्प बनाती हैं।
हैश आधारित संग्रह के साथ काम करते समय ध्यान देने योग्य सबसे महत्वपूर्ण बात यह है कि कुंजी ऐसी hashCode()
होनी चाहिए जो हमेशा वस्तु के जीवनकाल के लिए समान मूल्य लौटाए, क्योंकि यदि उस मूल्य को बदल दिया जाता है तो हैश आधारित संग्रह में पुरानी प्रविष्टि बनाई जाती है उस ऑब्जेक्ट का उपयोग करके पुनर्प्राप्त नहीं किया जा सकता है, इसलिए यह मेमोरी रिसाव का कारण होगा। चूंकि अपरिवर्तनीय वस्तुओं की स्थिति को बदला नहीं जा सकता है, इसलिए वे हैश आधारित संग्रह में कुंजी के रूप में एक शानदार विकल्प बनाते हैं। इसलिए, यदि आप हैश आधारित संग्रह के लिए कुंजी के रूप में अपरिवर्तनीय वस्तु का उपयोग कर रहे हैं, तो आप यह सुनिश्चित कर सकते हैं कि उसकी वजह से कोई स्मृति रिसाव नहीं होगा (बेशक वहाँ अभी भी स्मृति रिसाव हो सकता है जब कुंजी के रूप में उपयोग की जाने वाली वस्तु कहीं से संदर्भित नहीं होती है और, लेकिन यहाँ वह बात नहीं है)।
अपरिवर्तनीय वस्तुएँ ऐसे उदाहरण हैं जिनकी अवस्थाएँ एक बार आरंभ होने के बाद नहीं बदलती हैं। ऐसी वस्तुओं का उपयोग विशिष्ट आवश्यकता है।
कैशिंग उद्देश्य के लिए अपरिवर्तनीय वर्ग अच्छा है और यह थ्रेड सुरक्षित है।
अपरिवर्तनीयता के आधार पर आप यह सुनिश्चित कर सकते हैं कि अंतर्निहित अपरिवर्तनीय वस्तु के व्यवहार / स्थिति को बदलना नहीं है, इसके साथ ही आपको अतिरिक्त संचालन करने का अतिरिक्त लाभ मिलेगा:
आप आसानी के साथ कई कोर / प्रोसेसिंग ( समवर्ती / समानांतर प्रसंस्करण ) का उपयोग कर सकते हैं (जैसा कि संचालन का अनुक्रम अब मायने नहीं रखेगा।)
महंगे संचालन के लिए कैशिंग कर सकते हैं (जैसा कि आप एक ही
परिणाम के बारे में सुनिश्चित हैं )।
आसानी से डिबगिंग कर सकते हैं (क्योंकि रन का इतिहास
अब चिंता का विषय नहीं होगा)
अंतिम कीवर्ड का उपयोग करना जरूरी नहीं है कि कुछ अपरिवर्तनीय हो:
public class Scratchpad {
public static void main(String[] args) throws Exception {
SomeData sd = new SomeData("foo");
System.out.println(sd.data); //prints "foo"
voodoo(sd, "data", "bar");
System.out.println(sd.data); //prints "bar"
}
private static void voodoo(Object obj, String fieldName, Object value) throws Exception {
Field f = SomeData.class.getDeclaredField("data");
f.setAccessible(true);
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.set(obj, "bar");
}
}
class SomeData {
final String data;
SomeData(String data) {
this.data = data;
}
}
केवल एक उदाहरण प्रदर्शित करने के लिए कि प्रोग्रामर त्रुटि को रोकने के लिए "अंतिम" कीवर्ड है, और बहुत अधिक नहीं। जबकि अंतिम कीवर्ड की कमी वाले मान को पुन: असाइन करना दुर्घटना से आसानी से हो सकता है, मान को बदलने के लिए इस लंबाई पर जाने को जानबूझकर किया जाना होगा। यह प्रलेखन के लिए और प्रोग्रामर त्रुटि को रोकने के लिए है।
पुनरावर्ती एल्गोरिदम को कोड करते समय अपरिवर्तनीय डेटा संरचनाएं भी मदद कर सकती हैं। उदाहरण के लिए, कहें कि आप 3SAT समस्या को हल करने का प्रयास कर रहे हैं । एक तरीका निम्नलिखित है:
यदि आपके पास समस्या का प्रतिनिधित्व करने के लिए एक परिवर्तनशील संरचना है, तो जब आप TRUE शाखा में उदाहरण को सरल करते हैं, तो आपको या तो निम्न करना होगा:
हालाँकि यदि आप इसे चतुर तरीके से कोड करते हैं, तो आपके पास एक अपरिवर्तनीय संरचना हो सकती है, जहाँ कोई भी ऑपरेशन समस्या का अद्यतन (लेकिन अभी भी अपरिवर्तनीय) संस्करण देता है (समान String.replace
- यह स्ट्रिंग को प्रतिस्थापित नहीं करता है, बस आपको एक नया देता है )। इसे लागू करने का भोला तरीका "अपरिवर्तनीय" संरचना है, बस कॉपी करें और किसी भी संशोधन पर एक नया बना दें, यह एक दूसरे के साथ एक दूसरे के साथ मिलकर समाधान को कम कर सकता है, जो सभी उपरि के साथ है, लेकिन आप इसे अधिक तरीके से कर सकते हैं प्रभावशाली तरीका।
अपरिवर्तनीय वर्गों के लिए "आवश्यकता" के कारणों में से एक संदर्भ द्वारा सब कुछ पारित करने और किसी वस्तु के केवल-पढ़ने के विचारों के लिए कोई समर्थन न होने का संयोजन है (यानी सी ++ + s) const
) के ।
पर्यवेक्षक पैटर्न के समर्थन वाले वर्ग के साधारण मामले पर विचार करें:
class Person {
public string getName() { ... }
public void registerForNameChange(NameChangedObserver o) { ... }
}
यदि string
अपरिवर्तनीय नहीं थे, तो Person
वर्ग के लिए registerForNameChange()
सही तरीके से लागू करना असंभव होगा , क्योंकि कोई व्यक्ति निम्नलिखित सूचना लिख सकता है, किसी अधिसूचना को ट्रिगर किए बिना व्यक्ति के नाम को प्रभावी ढंग से संशोधित कर सकता है।
void foo(Person p) {
p.getName().prepend("Mr. ");
}
सी ++ में, getName()
रिटर्निंग का const std::string&
संदर्भ द्वारा लौटने और उत्परिवर्तकों तक पहुंच को रोकने का प्रभाव है, जिसका अर्थ है कि उस संदर्भ में अपरिवर्तनीय कक्षाएं आवश्यक नहीं हैं।
वे हमें गारंटी भी देते हैं। अपरिवर्तनीयता की गारंटी का मतलब है कि हम उन पर विस्तार कर सकते हैं और दक्षता के लिए नए पेटेंट बना सकते हैं जो अन्यथा संभव नहीं हैं।
अपरिवर्तनीय वर्गों की एक विशेषता जिसे अभी तक बाहर नहीं बुलाया गया है: एक गहरी-अपरिवर्तनीय वर्ग वस्तु के संदर्भ को संग्रहीत करना राज्य में निहित सभी को संग्रहीत करने का एक कुशल साधन है। मान लीजिए कि मेरे पास एक परिवर्तनशील वस्तु है जो 50K मूल्य की राज्य सूचना रखने के लिए एक गहरी-अपरिवर्तनीय वस्तु का उपयोग करती है। मान लीजिए, आगे, कि मैं 25 मौकों पर अपनी मूल (परस्पर) वस्तु की "प्रतिलिपि" बनाना चाहता हूं (उदाहरण के लिए "पूर्ववत करें" बफर); राज्य प्रतिलिपि कार्यों के बीच बदल सकता है, लेकिन आमतौर पर ऐसा नहीं होता है। उत्परिवर्तित वस्तु की "प्रतिलिपि" बनाने के लिए बस इसकी अपरिवर्तनीय स्थिति के संदर्भ की प्रतिलिपि बनाने की आवश्यकता होगी, इसलिए 20 प्रतियां केवल 20 संदर्भों के लिए राशि होगी। इसके विपरीत, यदि राज्य 50K मूल्य की उत्परिवर्तित वस्तुओं में रखे गए थे, तो 25 प्रतियों में से प्रत्येक को 50K मूल्य के डेटा की अपनी प्रति का उत्पादन करना होगा; सभी 25 प्रतियों को धारण करने के लिए अधिक-से-अधिक डेटा के एक मेगा मूल्य पर होल्डिंग की आवश्यकता होगी। भले ही पहली कॉपी ऑपरेशन डेटा की एक प्रति उत्पन्न करेगा जो कभी नहीं बदलेगा, और अन्य 24 संचालन सिद्धांत में बस उसी को वापस संदर्भित कर सकते हैं, ज्यादातर कार्यान्वयन में दूसरी वस्तु के लिए कोई रास्ता नहीं होगा। यह जानने के लिए कि एक अपरिवर्तनीय प्रति पहले से मौजूद है (*)।
(*) एक पैटर्न जो कभी-कभी उपयोगी हो सकता है वह है उत्परिवर्तित वस्तुओं के लिए दो क्षेत्रों के लिए अपने राज्य को धारण करने के लिए - एक परिवर्तनशील रूप में और एक अपरिवर्तनीय रूप में। वस्तुओं को परस्पर या अपरिवर्तनीय के रूप में कॉपी किया जा सकता है, और एक या दूसरे संदर्भ सेट के साथ जीवन शुरू होगा। जैसे ही वस्तु अपने राज्य को बदलना चाहती है, यह अपरिवर्तनीय संदर्भ को उत्परिवर्तित एक (यदि यह पहले से नहीं किया गया है) की प्रतिलिपि बनाता है और अपरिवर्तनीय को अमान्य कर देता है। जब ऑब्जेक्ट को अपरिवर्तनीय के रूप में कॉपी किया जाता है, यदि इसका अपरिवर्तनीय संदर्भ सेट नहीं किया जाता है, तो एक अपरिवर्तनीय प्रतिलिपि बनाई जाएगी और अपरिवर्तनीय संदर्भ को इंगित किया जाएगा। इस दृष्टिकोण को "लिखने पर पूर्णरूपेण कॉपी" की तुलना में कुछ और कॉपी ऑपरेशन्स की आवश्यकता होगी (उदाहरण के लिए किसी ऑब्जेक्ट को कॉपी करने के लिए पूछना जो अंतिम कॉपी के बाद से कॉपी किए गए ऑपरेशन की आवश्यकता होगी,
अपरिवर्तनीय वर्ग क्यों?
एक बार किसी वस्तु को तुरंत बदल देने के बाद उसे जीवनकाल में नहीं बदला जा सकता है। जो इसे धागे को सुरक्षित भी बनाता है।
उदाहरण :
स्पष्ट रूप से स्ट्रिंग, इंटेगर और बिगडेसीमल आदि एक बार इन मूल्यों के बनने के बाद जीवनकाल में नहीं बदले जा सकते।
उपयोग-मामला: एक बार डेटाबेस कनेक्शन ऑब्जेक्ट को इसके कॉन्फ़िगरेशन मूल्यों के साथ बनाया जाता है, तो आपको इसके राज्य को बदलने की आवश्यकता नहीं हो सकती है जहां आप एक अचल वर्ग का उपयोग कर सकते हैं
प्रभावी जावा से; एक अपरिवर्तनीय वर्ग बस एक ऐसा वर्ग है जिसके उदाहरणों को संशोधित नहीं किया जा सकता है। प्रत्येक उदाहरण में शामिल सभी जानकारी तब प्रदान की जाती है जब इसे बनाया जाता है और ऑब्जेक्ट के जीवनकाल के लिए तय किया जाता है। जावा प्लेटफ़ॉर्म पुस्तकालयों में कई अपरिवर्तनीय कक्षाएं शामिल हैं, जिसमें स्ट्रिंग, बॉक्सिंग आदिम कक्षाएं, और बिगइन्टे- जीर और बिगडेसीमल शामिल हैं। इसके कई अच्छे कारण हैं: अपरिवर्तनीय कक्षाएं म्यूट करने योग्य कक्षाओं की तुलना में डिजाइन, कार्यान्वयन और उपयोग करना आसान हैं। वे त्रुटि के लिए कम प्रवण हैं और अधिक सुरक्षित हैं।