प्राइवेट क्लास मेथड कैसे बनाये?


216

निजी कक्षा विधि बनाने का यह तरीका कैसे काम करता है:

class Person

  def self.get_name
    persons_name
  end

  class << self

    private

    def persons_name
      "Sam"
    end
  end
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name  #=> raises "private method `persons_name' called for Person:Class (NoMethodError)"

लेकिन यह नहीं है:

class Person

  def self.get_name
    persons_name
  end

  private

  def self.persons_name
    "Sam"
  end
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name

7
मैंने इस लेख को निजी कक्षा के तरीकों को बनाने के तरीकों पर चर्चा करते हुए देखा और सोचा कि यह अच्छा था: jakeyesbeck.com/2016/01/24/ruby-pStreet-class-methods/…
नाथन लॉन्ग

जवाबों:


265

privateयदि आप किसी विधि को किसी स्पष्ट वस्तु (आपके मामले में self) में परिभाषित कर रहे हैं तो काम नहीं करता है । आप private_class_methodकक्षा के तरीकों को निजी के रूप में परिभाषित करने के लिए उपयोग कर सकते हैं (या जैसा आप वर्णित है)।

class Person
  def self.get_name
    persons_name
  end

  def self.persons_name
    "Sam"
  end

  private_class_method :persons_name
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name

वैकल्पिक रूप से (रूबी 2.1+ में), क्योंकि एक विधि परिभाषा विधि नाम का प्रतीक लौटाती है, आप निम्नानुसार भी इसका उपयोग कर सकते हैं:

class Person
  def self.get_name
    persons_name
  end

  private_class_method def self.persons_name
    "Sam"
  end
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name

105

ExiRe ने लिखा:

माणिक का ऐसा व्यवहार वास्तव में निराशाजनक है। मेरा मतलब है कि अगर आप निजी सेल्फ.method में जाते हैं तो यह निजी नहीं है। लेकिन अगर आप इसे कक्षा << आत्म के लिए स्थानांतरित करते हैं तो यह अचानक काम करता है। यह सिर्फ घृणित है।

यह शायद भ्रमित है, निराशा होती है यह अच्छी तरह से हो सकता है, लेकिन घृणित यह निश्चित रूप से नहीं है।

यह सही समझ में आता है एक बार आप रूबी के ऑब्जेक्ट मॉडल को समझते हैं और इसी विधि प्रवाह देखने , खासकर जब ध्यान में ले जा रहा है कि privateहै नहीं एक पहुँच / दृश्यता संशोधक, लेकिन वास्तव में एक विधि कॉल (अपने प्राप्तकर्ता के रूप में वर्ग के साथ) के रूप में चर्चा यहाँ ... रूबी में "निजी अनुभाग" जैसी कोई चीज नहीं है ।

निजी आवृत्ति विधियों को परिभाषित करने के लिए , आप privateबाद में परिभाषित तरीकों के लिए डिफ़ॉल्ट दृश्यता को निजी में सेट करने के लिए इंस्टेंस क्लास पर कॉल करते हैं ... और इसलिए यह क्लास के क्लास पर कॉल करके निजी क्लास के तरीकों को परिभाषित करने के लिए सही समझ में आता है private। इसके मेटाक्लस।

अन्य मुख्यधारा, स्व-घोषित ओओ भाषाएँ आपको कम भ्रमित करने वाली वाक्य रचना दे सकती हैं, लेकिन आप निश्चित रूप से रूबी की मेटाप्रोग्रामिंग सुविधाओं की शक्ति के बिना एक भ्रमित और कम सुसंगत (असंगत?) ऑब्जेक्ट मॉडल के खिलाफ व्यापार करते हैं ।


इसलिए अगर मैं सही तरीके से समझूं, तो माणिक के पास कोई एक्सेस संशोधक कीवर्ड (सार्वजनिक, निजी और संरक्षित) नहीं है, बल्कि उसके पास एक्सेसिफ़ाइटर मेथड (सार्वजनिक, निजी, संरक्षित) हैं? क्या यह कुछ ऐसा है जिसे उचित कीवर्ड एक्सेस संशोधक को लागू करने के लिए Matz के लिए रूबी बग ट्रैकर पर लाया जाना चाहिए या यह अपेक्षित व्यवहार है?
एडवर्ड

13
@Edward यह इस तरह से डिज़ाइन किया गया है junichiito.blogspot.co.uk/2012/03/… । क्यों "उचित"?
आईएन

1
इसके बाद से, करने के बजाय private_class_method :method_nameआप कर सकते हैं private_class_method def method_name...
bjt38

send(private_method)वस्तु के बाहर भी सुलभ है।
स्टीवेंसपिल

1
@ bjt38 स्पष्टता के लिए, यह होगाprivate_class_method def self.method_name
टॉम

78

डिफ़ॉल्ट रूप से सभी वर्ग विधियाँ सार्वजनिक हैं। उन्हें निजी बनाने के लिए आप मॉड्यूल का उपयोग कर सकते हैं # Private_class_method जैसे @tjwallace ने लिखा हो या उन्हें अलग तरीके से परिभाषित करें, जैसा आपने किया था:

class << self

  private

  def method_name
    ...
  end
end

class << selfस्वयं के एकल वर्ग को खोलता है, ताकि वर्तमान आत्म वस्तु के लिए तरीकों को फिर से परिभाषित किया जा सके। इसका उपयोग वर्ग / मॉड्यूल ("स्थिर") विधि को परिभाषित करने के लिए किया जाता है। केवल वहाँ, निजी तरीकों को परिभाषित करना वास्तव में आपको निजी वर्ग के तरीके देता है।


17

पूर्णता के लिए, हम निजी_क्लास_मेथोड को एक अलग पंक्ति में घोषित करने से भी बच सकते हैं। मुझे व्यक्तिगत रूप से यह उपयोग पसंद नहीं है, लेकिन यह जानने के लिए अच्छा है कि यह मौजूद है।

private_class_method  def self.method_name
 ....
end

5

मैं भी, रूबी (या इसके बारे में कम से कम मेरी जानकारी) इस क्षेत्र में निशान से कम लगता है। उदाहरण के लिए निम्नलिखित मैं क्या चाहता हूँ लेकिन अनाड़ी है,

class Frob
    attr_reader :val1, :val2

    Tolerance = 2 * Float::EPSILON

    def initialize(val1, val2)
        @val2 = val1
        @val2 = val2
        ...
    end

    # Stuff that's likely to change and I don't want part
    # of a public API.  Furthermore, the method is operating
    # solely upon 'reference' and 'under_test' and will be flagged as having
    # low cohesion by quality metrics unless made a class method.
    def self.compare(reference, under_test)
        # special floating point comparison
        (reference - under_test).abs <= Tolerance
    end
    private_class_method :compare

    def ==(arg)
        self.class.send(:compare, val1, arg.val1) &&
        self.class.send(:compare, val2, arg.val2) &&
        ...
    end
end

ऊपर दिए गए कोड के साथ मेरी समस्या यह है कि रूबी सिंटैक्स आवश्यकताओं और मेरे कोड गुणवत्ता मीट्रिक बोझिल कोड के लिए बनाया गया है। कोड के रूप में मैं चाहता हूँ दोनों काम करते हैं और मैट्रिक्स को शांत करने के लिए, मैं एक वर्ग विधि की तुलना () करना चाहिए। चूँकि मैं यह नहीं चाहता कि यह वर्ग 'पब्लिक एपीआई' का हिस्सा हो, इसलिए मुझे इसकी निजी ज़रूरत है, फिर भी 'निजी' अपने आप काम नहीं करता है। इसके बजाय मैं 'Private_class_method' या इस तरह के कुछ काम का उपयोग करने के लिए मजबूर हूं। यह बदले में, '== ()' में प्रत्येक चर I परीक्षण के लिए 'self.class.send (: Compar ...') के उपयोग को बाध्य करता है। अब यह थोड़ा सा अस्पष्ट है।


तथ्य यह है कि आप भेजने के लिए उपयोग करने की आवश्यकता है "कैसे" आप वर्ग विधियों निजी चिह्नित करने के लिए कुछ भी नहीं है। निजी तरीकों को "बाहर" से नहीं बुलाया जा सकता है।
पास्कल

4

उदाहरण के तरीकों को एक वर्ग परिभाषा ब्लॉक के अंदर परिभाषित किया गया है। वर्ग विधियों को एक वर्ग के सिंगलटन वर्ग पर सिंगलटन विधियों के रूप में परिभाषित किया जाता है, जिसे अनौपचारिक रूप से "मेटाक्लास" या "ईगेंसेलस" के रूप में भी जाना जाता है। privateएक कीवर्ड नहीं है, लेकिन एक विधि ( मॉड्यूल # निजी ) है।

यह विधि है self#private/ A#privateजो "टॉगल" करने के लिए सभी आगामी उदाहरण विधि परिभाषाओं के लिए निजी पहुँच पर जब तक टॉगल नहीं किया जाता है:

class A
  private
    def instance_method_1; end
    def instance_method_2; end
    # .. and so forth
end

जैसा कि पहले उल्लेख किया गया है, वर्ग विधियाँ वास्तव में एकल वर्ग पर परिभाषित एकल विधि हैं।

def A.class_method; end

या A के अनाम, एकल वर्ग की परिभाषा बॉडी को खोलने के लिए एक विशेष सिंटैक्स का उपयोग करना:

class << A
  def class_method; end
end

"मैसेज प्राइवेट" का रिसीवर - सेल्फ इनसाइड class Aक्लास ऑब्जेक्ट है। class << Aब्लॉक के अंदर सेल्फ एक और ऑब्जेक्ट है, सिंगलटन क्लास।

निम्न उदाहरण वास्तविकता में कॉल करने के लिए दो अलग- अलग प्राप्तकर्ता या लक्ष्य का उपयोग करते हुए, दो अलग-अलग तरीकों को निजी कहा जाता है । पहले भाग में, हम एक निजी उदाहरण विधि ("क्लास ए पर") को परिभाषित करते हैं, बाद में हम एक निजी क्लास पद्धति को परिभाषित करते हैं (वास्तव में ए के सिंगलटन क्लास ऑब्जेक्ट पर एक सिंगलटन विधि है)।

class A
  # self is A and private call "A.private()"
  private def instance_method; end

  class << self
    # self is A's singleton class and private call "A.singleton_class.private()"
    private def class_method; end
  end
end

अब, इस उदाहरण को थोड़ा फिर से लिखें:

class A
  private
    def self.class_method; end
end

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


-1

रूबी एक गरीब समाधान प्रदान करने के लिए लगता है। समझाने के लिए, एक साधारण C ++ उदाहरण से शुरू करें जो निजी वर्ग विधियों तक पहुँच दिखाता है:

#include <iostream>

class C
{
    public:
        void instance_method(void)
        {
            std::cout << "instance method\n";
            class_method();  // !!! LOOK !!! no 'send' required. We can access it
                             // because 'private' allows access within the class
        }
    private:
        void static class_method(void) { std::cout << "class method\n"; }
};

int main()
{
    C c;

    c.instance_method(); // works
    // C::class_method() does not compile - it's properly private
    return 0;
}

ऊपर भाग रहा है

   % ./a.out
   instance method
   class method

अब रूबी समकक्ष प्रदान नहीं करती है। रूबी के नियम, मुझे लगता है, यह है कि निजी तरीकों को एक रिसीवर के साथ एक्सेस नहीं किया जाना चाहिए। अर्थात्,

inst.pvt_method  # FAILS
pvt_method # WORKS only within the class (good)

यह निजी उदाहरण के तरीकों के लिए ठीक है, लेकिन निजी वर्ग के तरीकों के साथ समस्याओं का कारण बनता है।

मैं रूबी को इस तरह से काम करना चाहूंगा:

class C
    def instance_method
        STDOUT << "instance method\n"

        # Simple access to the private class method would be nice:
        class_method   # DOES NOT WORK. RUBY WON'T FIND THE METHOD
        C.class_method # DOES NOT WORK. RUBY WON'T ALLOW IT

        # ONLY THIS WORKS. While I am happy such capability exists I think
        # the way 'send' should be used is when the coder knows he/she is
        # doing a no-no.  The semantic load on the coder for this is also
        # remarkably clumsy for an elegant language like ruby.
        self.class.send(:class_method)
    end

    private_class_method def self.class_method() STDOUT << "class method\n"; end
end

लेकिन, अफसोस, ऊपर काम नहीं करता है। क्या कोई बेहतर तरीका जानता है?

जब मैं किसी विधि से पहले 'सेंड' देखता हूं, तो यह एक स्पष्ट संकेत है कि कोड एपीआई के डिजाइनर के इरादे का उल्लंघन कर रहा है, लेकिन इस मामले में डिजाइन को विशेष रूप से निजी कॉल पद्धति की श्रेणी कॉल की आवृत्ति विधि है।


-14

रूबी 2.3.0 के रूप में

class Check
  def self.first_method
    second_method
  end

  private
  def self.second_method
    puts "well I executed"
  end
end

Check.first_method
#=> well I executed

मैं private def self.second_methodप्रत्येक विधि संकेतन से पहले यह कोशिश कर रहा था , जो मेरे रूबी 2.3.3 पर काम नहीं कर रहा था। लेकिन यह अंकन मेरे लिए काम करता है।
एमिल व्रजदग्ज

11
यह गलत है, क्योंकि कॉलिंग Check.second_methodएक समस्या के बिना भी काम करेगी, इसलिए यह वास्तव में निजी नहीं है।
डेविन

1
यह इस कोशिश नहीं करेगाprivate_class_method :second_method
राजा SABRI
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.