2012-01-03 16 views
10

पुस्तक Java Concurrency In Practice में यह परिवर्तनशील वस्तुओं संगामिति वार बनाम "प्रभावी रूप से अपरिवर्तनीय" वस्तुओं के फायदे बताते हैं। लेकिन यह समझ में नहीं आता है कि "प्रभावी ढंग से अपरिवर्तनीय" वस्तुएं पर वास्तव में अपरिवर्तनीय वस्तुओं से अधिक लाभ प्रदान करती हैं।प्रभावी ढंग से अपरिवर्तनीय वस्तुओं को समझ में आता है?

और मुझे यह नहीं मिला: क्या आप हमेशा उस समय वास्तव में अपरिवर्तनीय वस्तु का निर्माण नहीं कर सकते जब आप सुरक्षित रूप से "प्रभावी रूप से अपरिवर्तनीय" ऑब्जेक्ट को प्रकाशित करने का निर्णय लेते? (आपके "सुरक्षित प्रकाशन" करने के बजाय आप वास्तव में अपरिवर्तनीय वस्तु का निर्माण करेंगे और यह है)

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

तो "प्रभावी रूप से अपरिवर्तनीय" वस्तु और उनके "सुरक्षित प्रकाशन" सिर्फ बुरा डिजाइन या गरीब एपीआई का मामला है?

कहाँ आप एक प्रभावी रूप से अपरिवर्तनीय वस्तु का उपयोग करने के लिए मजबूर किया जाएगा और सुरक्षित रूप से प्रकाशित करने के लिए जहाँ आप एक बहुत बेहतर वास्तव में अपरिवर्तनीय वस्तु का निर्माण नहीं कर सकता है के लिए मजबूर हो?

उत्तर

9

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

1

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

+0

इस दृष्टिकोण का कोई भी उदाहरण उपलब्ध है? महान उदाहरण और स्पष्टीकरण के लिए – user77115

3

परिपत्र immutables के लिए:

class Foo 
{ 
    final Object param; 
    final Foo other; 

    Foo(Object param, Foo other) 
    { 
     this.param = param; 
     this.other = other; 
    } 

    // create a pair of Foo's, A=this, B=other 
    Foo(Object paramA, Object paramB) 
    { 
     this.param = paramA; 
     this.other = new Foo(paramB, this); 
    } 

    Foo getOther(){ return other; } 
} 



// usage 
Foo fooA = new Foo(paramA, paramB); 
Foo fooB = fooA.getOther(); 
// publish fooA/fooB (unsafely) 

एक सवाल है, के बाद से fooA की this निर्माता अंदर लीक कर रहा है, fooA अभी भी एक धागा सुरक्षित अपरिवर्तनीय है? यही है, अगर कोई अन्य धागा fooB.getOther().param पढ़ता है, तो क्या यह paramA देखने की गारंटी है? जवाब हां है, क्योंकि thisफ्रीज कार्रवाई से पहले किसी अन्य धागे पर लीक नहीं किया गया है; हम यह साबित करने के लिए spec द्वारा आवश्यक एचबी/डीसी/एमसी ऑर्डर स्थापित कर सकते हैं कि paramA पढ़ने के लिए एकमात्र दृश्यमान मूल्य है।

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

कभी सोच हम को लगता है कि यह एक बहुत अच्छा विचार है सर्वोच्च तंग आ चुके हैं क्यों?

गहरी समस्या जावा की कमी सुरक्षित प्रकाशन के लिए एक सामान्य सस्ते फेंस है जो अस्थिर से सस्ता है। जावा में केवल final फ़ील्ड हैं; किसी कारण से, बाड़ अन्यथा उपलब्ध नहीं है।

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

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

+0

+1। इसके अलावा मैंने "अंतिम" का जिक्र नहीं किया लेकिन वास्तव में हमें इसका उपयोग करना है ... दोनों अर्थों के बारे में: यह और भी भ्रमित है कि यह देखा गया है कि * अंतिम * विधियों पर भी लागू किया जा सकता है लेकिन मैं digress;) मुझे कन्स्ट्रक्टर उदाहरण पसंद है हालांकि कोई भी कारखाने और/या एक धाराप्रवाह इंटरफ़ेस का उपयोग करके ऐसा कर सकता है। – NoozNooz42

0

मान लीजिए एक से पांच गुणों के साथ एक अपरिवर्तनीय वर्ग Foo, आदि Alpha नाम है, Beta, है, और एक WithAlpha, WithBeta, आदि तरीकों जो एक उदाहरण है, जिसमें विशेष रूप से साथ छोड़कर मूल के समान है वापस आ जाएगी प्रदान करने के लिए चाहता है संपत्ति बदल गई यदि वर्ग वास्तव में और गहराई से अपरिवर्तनीय है, तो विधियों को फॉर्म लेना होगा:

 
Foo WithAlpha(string newAlpha) 
{ 
    return new Foo(newAlpha, Beta, Gamma, Delta, Epsilon); 
} 

Foo WithBeta(string newBeta) 
{ 
    return new Foo(Alpha, NewBeta, Gamma, Delta, Epsilon); 
} 

आईक। "खुद को दोहराएं" (डीआरवाई) सिद्धांतों का भारी उल्लंघन। इसके अलावा, कक्षा में एक नई संपत्ति जोड़ने के लिए उन तरीकों में से प्रत्येक को जोड़ने की आवश्यकता होगी।

दूसरी ओर, यदि प्रत्येक Foo एक आंतरिक FooGuts जो एक प्रति निर्माता शामिल आयोजित की, एक के बजाय की तरह कुछ कर सकता है:

 
Foo WithAlpha(string newAlpha) 
{ 
    FooGuts newGuts = new FooGuts(Guts); // Guts is a private or protected field 
    newGuts.Alpha = newAlpha; 
    return new Foo(newGuts); // Private or protected constructor 
} 

प्रत्येक विधि के लिए कोड की लाइनों की संख्या बढ़ गई है, लेकिन विधियों को अब किसी भी संपत्ति के लिए कोई संदर्भ देने की आवश्यकता नहीं है, जिसमें वे "दिलचस्पी नहीं रखते हैं। ध्यान दें कि Foo अप्रत्याशित नहीं हो सकता है अगर उसके निर्माता को FooGuts के साथ बुलाया गया था, जिसके लिए कोई बाहरी संदर्भ मौजूद था, इसका कन्स्ट्रक्टर केवल पहुंच योग्य है कोड जो निर्माण के बाद इस तरह के किसी भी संदर्भ को बनाए रखने के लिए भरोसा नहीं है।

संबंधित मुद्दे