मैं कल रूबी के बारे में पढ़ रहा था और सिंगलटन की अवधारणा तक पहुंचा, जिसका उल्लेख एक से अधिक बार कक्षा को तुरंत चालू करने से बचने के लिए किया गया था।

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

उदाहरण:

@browser ||= Browser.new

क्या कुछ स्थितियों में कोई अंतर या लाभ है, जो सिंगलटन के उपयोग को बेहतर बनाएगा?

1
mickael 21 जून 2018, 12:16

2 जवाब

सबसे बढ़िया उत्तर

रूबी में ||= ऑपरेटर एक चर के लिए एक मान सेट करता है यदि चर अपरिभाषित है या इसमें एक गलत मान (शून्य या गलत) है।

a = 1
a ||= 2 # a is already set to 1 so it stays 1.

a = false
a ||= 1 # a was falsey, it is now set to 1.

इसका उपयोग अक्सर अनावश्यक पुनर्गणना को कम करने के लिए विधि वापसी मूल्यों को याद रखने के लिए किया जाता है:

class Foo
  def value
    @value ||= 1+1
  end
end

Foo.new.value # @value was undefined so it set to 1+1 = 2
Foo.new.value # @value was already defined so return it instead of recalculating

सिंगलटन वर्ग एक ऐसा वर्ग है जिसमें केवल एक उदाहरण हो सकता है।

एक नियमित गैर सिंगलटन वर्ग:

class Foo
end

# create two instances:
foo1 = Foo.new
foo2 = Foo.new

foo1 == foo2 # => false 

एक सिंगलटन वर्ग:

require 'singleton'
class Foo
  include Singleton

  def test
    "hello"
  end
end

# you can't create an instance:
foo = Foo.new # => NoMethodError (private method `new' called for Foo:Class)

# there is one global instance:
foo1 = Foo.instance
foo2 = Foo.instance
foo1 == foo2 # => true

# the Singleton module does not enable you to call the instance methods directly:
Foo.test # => NoMethodError (private method `test' called for Foo:Class)
Foo.instance.test # => "hello"

मुझे नहीं लगता कि ऐसे कई मामले हैं जहां सिंगलटन क्लास वास्तव में किसी समस्या का सबसे अच्छा समाधान है।

1
Kimmo Lehto 21 जून 2018, 15:02

||= का उपयोग किसी मान को याद रखने करने के लिए किया जाता है। उदाहरण के लिए, यदि आपके पास एक महंगा ऑपरेशन करने या एक अलग मूल्य लौटाने का कोई तरीका है:

class Foo
  def now
    Time.now
  end
end

f = Foo.new
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:59 +0200
f.now #=> 2018-06-21 12:00:02 +0200

और आप उस मान को कैश करना चाहेंगे, ||= आपका मित्र है:

class Foo
  def now
    @now ||= Time.now
  end
end

f = Foo.new
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200

पहली कॉल Time.now को कॉल करती है और परिणाम @now को असाइन करती है। बाद की कॉलें दाईं ओर का मूल्यांकन किए बिना केवल @now वापस आती हैं। इसलिए, Time.now को केवल एक बार कॉल किया जाता है और विधि का रिटर्न मान अब और नहीं बदलता है।

और क्योंकि @now एक इंस्टेंस चर है, इसलिए प्रति उदाहरण एक अलग मान संग्रहीत किया जाता है:

f = Foo.new
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200

g = Foo.new
f.now #=> 2018-06-21 12:00:02 +0200
f.now #=> 2018-06-21 12:00:02 +0200
f.now #=> 2018-06-21 12:00:02 +0200

दूसरी ओर एक singleton सुनिश्चित करता है कि एक (और केवल) एक) किसी दिए गए वर्ग का उदाहरण (प्रति प्रक्रिया), उदाहरण के लिए:

require 'singleton'

class Foo
  include Singleton

  def now
    @now ||= Time.now
  end
end

f = Foo.instance
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200

g = Foo.instance
g.now #=> 2018-06-21 11:59:56 +0200
g.now #=> 2018-06-21 11:59:56 +0200

ऐसा इसलिए है क्योंकि f और g एक ही वस्तु को संदर्भित करते हैं। Singleton सहित new या allocate के माध्यम से कोई अन्य उदाहरण बनाने की क्षमता:

Foo.new      #=> NoMethodError
Foo.allocate #=> NoMethodError
2
Stefan 21 जून 2018, 13:22