2009-10-14 4 views
25

मुझे यह समझने में थोड़ी देर लग गई कि कैसे निजी रूबी में काम करते हैं, और यह वास्तव में मुझे बहुत अजीब होने के रूप में मारता है। क्या किसी को पता है कि निजी तरीकों के तरीके को संभालने के अच्छे कारण हैं या नहीं? क्या यह सिर्फ ऐतिहासिक कारण है? या कार्यान्वयन के कारण? या क्या अच्छे ठोस तार्किक कारण हैं (यानी अर्थात्)?रुबी में जिस तरह से काम करता है, 'निजी' के लिए काम करने के अच्छे कारण हैं?

उदाहरण के लिए: तर्ज पर

class Person 
    private 
    attr_reader :weight 
end 

class Spy < Person 
private 
    attr_accessor :code 
public 
    def test 
    code   #(1) OK: you can call a private method in self 
    Spy.new.code #(2) ERROR: cannot call a private method on any other object 
    self.code  #(3) ERROR!!! cannot call a private method explicitly on 'self' 
    code="xyz" #(4) Ok, it runs, but it actually creates a local variable!!! 
    self.code="z" #(5) OK! This is the only case where explicit 'self' is ok 
    weight  #(6) OK! You can call a private method defined in a base class 
    end 
end 
  • रूबी के व्यवहार (1), (2) और (5) उचित लगता है।
  • तथ्य यह है कि (6) ठीक है थोड़ा अजीब है, खासकर जावा और सी ++ से आ रहा है। इसके लिए कोई अच्छा कारण है?
  • मुझे वास्तव में समझ में नहीं आता क्यों (3) विफल रहता है! एक स्पष्टीकरण, कोई भी?
  • लाइन (4) की समस्या व्याकरण में एक अस्पष्टता की तरह दिखती है, जिसका 'निजी' से कोई लेना-देना नहीं है।

कोई भी विचार?

+1

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

उत्तर

30

आप इसे उपयोगी public, private and protected. की रूबी की परिभाषा को पढ़ने के लिए (प्रवेश नियंत्रण पर जाएं) मिल सकती है

रूबी के निजी जावा के संरक्षित के अनुरूप है। जावा के निजी के रूबी बराबर नहीं है। संपादित करें: यह समाधान अब रूबी ऑब्जेक्ट्स में जावा के निजी के आदर्श को फिक्र करने का तरीका प्रदान करता है।

निजी को विधियों/चर के रूप में परिभाषित किया गया है जो केवल को स्पष्ट रूप से बुलाया जा सकता है। यही कारण है कि कथन 2 और 3 विफल। दूसरे शब्दों में, किसी वर्ग या उप-वर्ग के संदर्भ में निजी सीमा विधियों/चर को परिभाषित किया जाता है जिसमें उन्हें परिभाषित किया जाता है। विरासत उप-वर्गों को निजी तरीकों से गुजरती है और इसलिए एक अंतर्निहित आत्म के साथ पहुंचा जा सकता है। (समझाते हुए कथन 6 क्यों काम करता है।)

मुझे लगता है कि आप सुरक्षित के करीब कुछ ढूंढ रहे हैं। जो जावा एक्सेसर्स के समान व्यवहार करता है जिन्हें दृश्यता नहीं दी जाती है (उदाहरण: सार्वजनिक, निजी, संरक्षित) अपने सभी कथन कार्यों को सुरक्षित रखने के लिए स्पाइ में निजी को बदलकर। संरक्षित विधियों को परिभाषित कक्षा या उनके उप-वर्गों के किसी भी उदाहरण से बुलाया जा सकता है। या तो स्पष्ट रूप से या स्पष्ट रूप से स्वयं को बुलाया जाता है, संरक्षित तरीकों के लिए मान्य बयान होते हैं जब तक कि कॉलर या तो कॉल का जवाब देने वाले ऑब्जेक्ट का वर्ग होता है, या उससे प्राप्त होता है।

class Person 
    private 
    attr_reader :weight 
end 

class Spy < Person 
protected 
    attr_accessor :code 
public 
    def test 
    code   #(1) OK: you can call a private method in self 
    Spy.new.code #(2) OK: Calling protected method on another instance from same class family or a descendant. 
    self.code  #(3) OK: Calling protected method on with explicit self is allowed with protected 
    code="xyz" #(4) Ok, it runs, but it actually creates a local variable!!! 
    self.code="z" #(5) OK! This is the only case where explicit 'self' is ok 
    weight  #(6) OK! You can call a private method defined in a base class 
    end 
end 

s = Spy.new 
s.test # succeeds 
s.code #(7) Error: Calling protected method outside of the class or its descendants. 

कथन के लिए 4. आप यह मानने में सही हैं कि यह अस्पष्टता से बचने के लिए है। यह रूबी की गतिशील प्रकृति के संभावित नुकसान के लिए अधिक सुरक्षा है। यह सुनिश्चित करता है कि आप बाद में कक्षा को खोलकर एक्सेसर्स को ओवरराइड नहीं कर सकते। एक ऐसी स्थिति जो उत्पन्न हो सकती है, उदाहरण के लिए दंडित कोड eval'ing द्वारा।

मैं केवल उन निर्णयों पर विचार कर सकता हूं जो इन व्यवहारों का कारण बनते हैं। इसके अधिकांश में मुझे लगता है कि यह भाषा की गतिशील प्रकृति के लिए नीचे आता है।

पीएस यदि आप वास्तव में चीजों को निजी की जावा परिभाषा देना चाहते हैं। केवल उस वर्ग के लिए उपलब्ध है जिसमें इसे परिभाषित किया गया है, यहां तक ​​कि उप-वर्ग भी नहीं। आप जिस विधियों तक पहुंच सीमित करना चाहते हैं, उनके संदर्भों को दूर करने के लिए आप अपनी कक्षाओं में एक self.inherited विधि जोड़ सकते हैं।

वजन बनाना उपवर्गों से दुर्गम विशेषता:

class Person 
    private 
    attr_reader :weight 

    def initialize 
    @weight = 5 
    end 

    def self.inherited(subclass) 
    subclass.send :undef_method, :weight 
    end 
end 

class Spy < Person 
private 
    attr_accessor :code 
public 
    def test 
    weight  
    end 
end 

Person.new.send(:weight) # => 5 
Spy.new.send(:weight) #=> Unhelpful undefined method error 

वह कुछ इस तरह के undef_method कॉल को बदलने के लिए अधिक अर्थपूर्ण हो सकता है:

def self.inherited(subclass) 
    subclass.class_eval %{ 
     def weight 
     raise "Private method called from subclass. Access Denied" 
     end 
    } 
    end 

जो एक बहुत अधिक उपयोगी त्रुटि प्रदान करता है और एक ही कार्यक्षमता।

अन्य कक्षाओं के लिए निजी विधियों को कॉल करने के लिए भेजना आवश्यक है। केवल यह साबित करने के लिए प्रयोग किया जाता है कि चीजें वास्तव में काम कर रही हैं।

जो हिंडसाइट में, निजी और सुरक्षित बेकार बनाता है। यदि आप अपने तरीकों की सुरक्षा के बारे में वास्तव में गंभीर हैं तो आपको उन्हें अवरोधित करने के लिए ओवरराइड करना होगा। निम्नलिखित कोड वस्तु की private_methods के आधार पर करता है:

def send_that_blocks_private_methods(method, *args) 
    if private_methods.include?(method.to_s) 
    raise "Private method #{method} cannot called be called with send." 
    else 
    send_that_allows_private_methods(method, *args) 
    end 
end 

alias_method :send_that_allows_private_methods, :send 
alias_method :send, :send_that_blocks_private_methods 
private :send_that_allows_private_methods 

आप private_methods के class_variable आप सभी निजी तरीकों की पहुंच को अस्वीकार करने के बजाय करने के लिए उपयोग ब्लॉक करना चाहते हैं निर्दिष्ट कर सकते हैं। आप निजी भेज सकते हैं, लेकिन ऑब्जेक्ट के बाहर से कॉलिंग के वैध उपयोग हैं।

+0

+1 आपके उत्तर के लिए धन्यवाद: यह बहुत स्पष्ट है। – MiniQuark

+0

"जो हिंडसाइट में है, निजी बनाता है और बेकार सुरक्षित है।" ज़रुरी नहीं। उनके पास संचार मूल्य है। अगर मैं 'Foo # चीजें' सार्वजनिक करता हूं, तो मैं कह रहा हूं "इसका उपयोग करें"; यदि निजी है, तो मैं कह रहा हूं "इस पर निर्भर न करें; यह कार्यान्वयन विस्तार है जिसे बदला जा सकता है।" यदि रूबी आपको 'फू' और ** ** '# चीजें' को फिर से परिभाषित करने जा रही है, तो यह आपको ** विधि ** तक पहुंचने देगी। लेकिन यह आपको 'प्रेषण' का उपयोग करता है ताकि आप जान सकें कि आप कुछ अप्रत्याशित कर रहे हैं। मुझे लगता है कि यह सिर्फ रुबी का दर्शन है। –

+0

क्या वह 'send_that_blocks_private_methods' [ऑब्जेक्ट # public_send'] के समान है (https://ruby-doc.org/core-2.4.1/Object.html#method-i-public_send)? –

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