में आलसी मूल्यांकन मेरे पास रूबी की स्थिति है, जहां एक ऑब्जेक्ट संभवतः बनाया जाना आवश्यक है, लेकिन यह सुनिश्चित नहीं है। और जैसा कि वस्तु का निर्माण महंगा हो सकता है, मैं इसे बनाने में बहुत उत्सुक नहीं हूं। मुझे लगता है कि यह आलसी लोडिंग के लिए एक स्पष्ट मामला है। मैं उस ऑब्जेक्ट को कैसे परिभाषित कर सकता हूं जो केवल तब नहीं बनाया जाता जब कोई इसे संदेश भेजता हो? ऑब्जेक्ट ब्लॉक में बनाया जाएगा। रूबी में सरल आलसी लोडिंग/प्रारंभिकरण के लिए कोई तरीका है? क्या ये चीजें कुछ रत्नों द्वारा समर्थित हैं, जो वस्तुओं के आलसी प्रारंभिकरण के विभिन्न मामलों के लिए विभिन्न समाधान प्रदान करती हैं? आपके सुझावों के लिए धन्यवाद!रुबी
रुबी
उत्तर
दो तरीके हैं।
सबसे पहले कॉलर आलसी ऑब्जेक्ट निर्माण को संभालने देना है। यह सबसे आसान समाधान है, और यह रूबी कोड में बहुत आम पैटर्न है।
class ExpensiveObject
def initialize
# Expensive stuff here.
end
end
class Caller
def some_method
my_object.do_something
end
def my_object
# Expensive object is created when my_object is called. Subsequent calls
# will return the same object.
@my_object ||= ExpensiveObject.new
end
end
दूसरा विकल्प वस्तु आरंभ में ही यह बताने के लिए lazily है। हम इसे प्राप्त करने के लिए हमारे वास्तविक वस्तु के चारों ओर एक प्रतिनिधि वस्तु बनाते हैं। यह दृष्टिकोण थोड़ा और मुश्किल है और अनुशंसित नहीं है जब तक आपके पास मौजूदा कॉलिंग कोड नहीं है जिसे आप संशोधित नहीं कर सकते हैं, उदाहरण के लिए।
class ExpensiveObject # Delegate
class RealExpensiveObject # Actual object
def initialize
# Expensive stuff here.
end
# More methods...
end
def initialize(*args)
@init_args = args
end
def method_missing(method, *args)
# Delegate to expensive object. __object method will create the expensive
# object if necessary.
__object__.send(method, *args)
end
def __object__
@object ||= RealExpensiveObject.new(*@init_args)
end
end
# This will only create the wrapper object (cheap).
obj = ExpensiveObject.new
# Only when the first message is sent will the internal object be initialised.
obj.do_something
तुम भी stdlib delegate
का उपयोग की चोटी पर इस का निर्माण करने के सकता है।
पहले उदाहरण में मुझे कॉलर क्लास का उदाहरण रखने की आवश्यकता है। सही? लेकिन मेरे लिए क्या अंतर है - कॉलर क्लास इंस्टेंस रखने या महंगे वर्ग उदाहरण रखने के लिए? – demas
पहले उदाहरण में, 'कॉलर' क्लास केवल उदाहरण है कि आप * एक्सपेन्डेबल ऑब्जेक्ट क्लास का उपयोग कैसे करेंगे। अंतर: आलस्य शुरू करें जहां आप * 'एक्सपेन्डेबल ऑब्जेक्ट' (सरल) का उपयोग करते हैं, या 'एक्सपेन्डेबल ऑब्जेक्ट' * स्वयं * (थोड़ा अधिक जटिल) में आलस्य पेश करते हैं। – molf
@molf: जब भी आप 'method_missing' ओवरराइड करते हैं, तो आपको * answer_to?' (या अधिमानतः 'answer_to_missing?' में 1.9.2 ओवरराइड करना होगा)। Http://blog.marc-andre.ca/2010/11/methodmissing-politely.html देखें – Nemo157
आप, lazily कोड के टुकड़े का मूल्यांकन करना चाहते हैं एक प्रॉक्सी का उपयोग:
class LazyProxy
# blank slate... (use BasicObject in Ruby 1.9)
instance_methods.each do |method|
undef_method(method) unless method =~ /^__/
end
def initialize(&lazy_proxy_block)
@lazy_proxy_block = lazy_proxy_block
end
def method_missing(method, *args, &block)
@lazy_proxy_obj ||= @lazy_proxy_block.call # evaluate the real receiver
@lazy_proxy_obj.send(method, *args, &block) # delegate unknown methods to the real receiver
end
end
फिर आप इस तरह उपयोग:
expensive_object = LazyProxy.new { ExpensiveObject.new }
expensive_object.do_something
आप की मनमाने ढंग से जटिल आरंभीकरण करने के लिए इस कोड का उपयोग कर सकते हैं महंगी सामान:
expensive_object = LazyProxy.new do
expensive_helper = ExpensiveHelper.new
do_really_expensive_stuff_with(expensive_helper)
ExpensiveObject.new(:using => expensive_helper)
end
expensive_object.do_something
यह कैसे काम करता है? आप एक LazyProxy ऑब्जेक्ट को तुरंत चालू करते हैं जिसमें प्रो में कुछ महंगी वस्तु बनाने के निर्देश दिए गए हैं। यदि आप प्रॉक्सी ऑब्जेक्ट पर कुछ विधि कॉल करते हैं, तो यह पहले महंगी ऑब्जेक्ट को तुरंत चालू करता है और उसके बाद विधि कॉल को प्रतिनिधि करता है।
अपना खुद का रोल करने के बजाय, आप [lazy.rb] (https://github.com/mental/lazy) का उपयोग कर सकते हैं। [रूबी बेस्ट प्रैक्टिस] (http://oreilly.com/catalog/978059652301//) पुस्तक में उपयोग के कुछ उदाहरण हैं, पृष्ठ 123 और आगे देखें। –