2012-02-13 17 views
9

इस noob प्रश्न के लिए खेद है के माध्यम से एक सरणी उदाहरण चर के संशोधन को रोकने के लिए ... चलो कहते हैं कि हमारे पास करते हैं:रूबी:</p> <pre><code>class TestMe attr_reader :array def initialize @array = (1..10).to_a end </code></pre> <p>अंत</p> <p>यह तो ऐसा करना संभव है: कैसे एक विशेषता पाठक

>> a = TestMe.new 
=> #<TestMe:0x00000005567228 @x=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]> 
>> a.array.map! &:to_s 
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] 
>> a.array 
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] 
  • यह स्पष्ट रूप से कैप्सूलीकरण के खिलाफ जाता है, doesn'it?
  • क्या सरणी चर को बदलने से जल्दी से सुरक्षित करने का कोई तरीका है?
  • ... या क्या मुझे हर बार मेरे इंस्टेंस वैरिएबल में "विनाशकारी" विधियों के साथ एक गहरी प्रति पाठक को लागू करने की आवश्यकता है?

संपादित मैं पढ़ कहीं यह एक सरणी उदाहरण चर का पर्दाफाश करने के "बुरा OO" है। यदि यह सच है, क्यों?

+2

मुझे लगता है कि आपका मूल प्रश्न आपके सेकेंड प्रश्न का उत्तर देता है कि सरणी आवृत्ति चर का खुलासा क्यों अच्छा नहीं है। –

+0

@ केएल -7: पूरी तरह से: डी –

उत्तर

11

आप attr_reader साथ ज्यादा कुछ नहीं कर सकता है, क्योंकि निम्नलिखित कोड उत्पन्न करता है:

def array; @array; end 

आप सरणी उदाहरण बेनकाब करने के लिए नहीं करना चाहते हैं, तो आप इस सरणी के गणनाकार लौट सकते हैं (बाहरी इटरेटर)। Enumerator एक अच्छा इटरेटर अबास्ट्रक्शन है और आपको मूल सरणी को संशोधित करने की अनुमति नहीं देता है।

def array; @array.to_enum; end 

encapsulation के लिए क्या अच्छा है और आपकी कक्षा के अवशोषण पर निर्भर नहीं है। आम तौर पर यह आंतरिक सरणी समेत किसी ऑब्जेक्ट की आंतरिक स्थिति का पर्दाफाश करने के लिए encapsulation के लिए अच्छा नहीं है। आप @array (या यहां तक ​​कि इसके पुनरावर्तक) को उजागर करने के बजाय @array पर संचालित कुछ विधियों का खुलासा करना चाह सकते हैं। कभी-कभी सरणी का पर्दाफाश करना ठीक होता है - हमेशा अपनी कक्षा के प्रस्तुतिकरण को देखें।

+1

कई वैध उत्तर, लेकिन मैंने ओओ पर आपकी व्याख्या के कारण आपका चयन किया। "किसी ऑब्जेक्ट की आंतरिक स्थिति" ने मुझे यह स्पष्ट कर दिया ... मैं स्वयं सिखाया गया हूं इसलिए मुझे अभी भी इन अवधारणाओं के चारों ओर अपने सिर को लपेटने में कठिनाई है। धन्यवाद। –

+0

+1, मुझे सरणी पर 'to_enum' को कॉल करने का विचार पसंद है। –

1

किसी भी उदाहरण उस पर बुला फ्रीज द्वारा अपरिवर्तनीय बन सकता है:

class TestMe 
attr_reader :array 

def initialize 
    @array = (1..10).to_a 
    @array.freeze 
end 
end 

a = TestMe.new 
a.array << 11 
# Error: can't modify frozen array 
+0

मिमी ... शायद मैं पर्याप्त स्पष्ट नहीं हुआ हूं। क्या होगा यदि मैं चाहता हूं कि मेरी सरणी अभी भी उत्परिवर्तनीय हो, लेकिन केवल एक लेखक के माध्यम से और पाठक के माध्यम से नहीं? –

+2

@m_x फिर 'attr_reader' का उपयोग न करें और कस्टम गेटर्स और सेटर्स को परिभाषित करें। –

5

कैसे गेटर से मूल सरणी की एक प्रति लौटने के बारे में:

class TestMe 

    attr_writer :array 

    def initialize 
    @array = (1..10).to_a 
    end 

    def array 
    @array.dup 
    end 

end 

उस मामले में आप सीधे संशोधित नहीं कर सकते मूल सरणी लेकिन विशेषता लेखक के साथ आप इसे नए (यदि आपको आवश्यकता हो) के साथ प्रतिस्थापित कर सकते हैं।

1

आप सरणी परिवर्तनशील रहने के लिए चाहते हैं, लेकिन नहीं जब पाठक के माध्यम से लौटे, तो सरणी है, लेकिन सिर्फ एक आवरण है जो उजागर करता है "सुरक्षित" तरीकों वापसी नहीं है, तो।

require 'forwardable' 
class SafeArray 
    extend Forwardable 
    def initialize(array); @array = array; end 
    # add the other methods you want to expose to the following line 
    def_delegators :@array, :size, :each, :[], :map 
end 

class TestMe 
    def initialize 
    @array = (1..10).to_a 
    end 
    def array 
    @wrapper ||= SafeArray.new(@array) 
    end 
end 
0

यह कैप्सूलीकरण के खिलाफ है, लेकिन हम ठीक से उस विशेषता का getter method ट्यूनिंग द्वारा समस्या का समाधान कर सकते हैं।

class TestMe 

def initialize 
    @array = (1..10).to_a 
end 

def array 
    Array.new(@array) 
end 

end 
0

आप अपने इंस्टेंस वैरिएबल के समान नाम के साथ एक विधि बनाकर encapsulate करते हैं लेकिन इसे बराबर चिह्न के साथ समाप्त करते हैं।अपने उदाहरण में है कि होगा:

def array= 
.. 
end 

कि विधि में आप जो कुछ भी यह है कि आप सरणी

1

के लिए नया मान निर्दिष्ट एक विशिष्ट विशेषता पाठक विधि है कि प्रतियां मूल विशेषता काम करता है बनाने से पहले करना चाहते हैं अच्छा, लेकिन ध्यान रखें कि न तो@array.dupऔर न हीArray.new(@array)गहरी प्रति करेगा। जिसका अर्थ है कि यदि आपके पास सरणी की सरणी है (जैसे [[1, 2], [3, 4]]), किसी भी सरणी के मान परिवर्तनों के विरुद्ध सुरक्षित नहीं होंगे।

return Marshal.load(Marshal.dump(@array)) 

Marshall.dump एक स्ट्रिंग है कि बाद वस्तु वापस उपज के लिए डीकोड किया जा सकता (प्रक्रिया serializing कहा जाता है) में किसी भी वस्तु को बदल देती है: रूबी में एक deepcopy करने के लिए, सबसे आसान तरीका मैंने पाया यह गया था। इस तरह, आपको दिए गए ऑब्जेक्ट की गहरी प्रतिलिपि मिलती है। आसान लेकिन थोड़ा गंदे मुझे स्वीकार करना है।