2010-03-17 16 views
15

में आलसी मूल्यांकन मेरे पास रूबी की स्थिति है, जहां एक ऑब्जेक्ट संभवतः बनाया जाना आवश्यक है, लेकिन यह सुनिश्चित नहीं है। और जैसा कि वस्तु का निर्माण महंगा हो सकता है, मैं इसे बनाने में बहुत उत्सुक नहीं हूं। मुझे लगता है कि यह आलसी लोडिंग के लिए एक स्पष्ट मामला है। मैं उस ऑब्जेक्ट को कैसे परिभाषित कर सकता हूं जो केवल तब नहीं बनाया जाता जब कोई इसे संदेश भेजता हो? ऑब्जेक्ट ब्लॉक में बनाया जाएगा। रूबी में सरल आलसी लोडिंग/प्रारंभिकरण के लिए कोई तरीका है? क्या ये चीजें कुछ रत्नों द्वारा समर्थित हैं, जो वस्तुओं के आलसी प्रारंभिकरण के विभिन्न मामलों के लिए विभिन्न समाधान प्रदान करती हैं? आपके सुझावों के लिए धन्यवाद!रुबी

+0

अपना खुद का रोल करने के बजाय, आप [lazy.rb] (https://github.com/mental/lazy) का उपयोग कर सकते हैं। [रूबी बेस्ट प्रैक्टिस] (http://oreilly.com/catalog/978059652301//) पुस्तक में उपयोग के कुछ उदाहरण हैं, पृष्ठ 123 और आगे देखें। –

उत्तर

31

दो तरीके हैं।

सबसे पहले कॉलर आलसी ऑब्जेक्ट निर्माण को संभालने देना है। यह सबसे आसान समाधान है, और यह रूबी कोड में बहुत आम पैटर्न है।

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 का उपयोग की चोटी पर इस का निर्माण करने के सकता है।

+0

पहले उदाहरण में मुझे कॉलर क्लास का उदाहरण रखने की आवश्यकता है। सही? लेकिन मेरे लिए क्या अंतर है - कॉलर क्लास इंस्टेंस रखने या महंगे वर्ग उदाहरण रखने के लिए? – demas

+0

पहले उदाहरण में, 'कॉलर' क्लास केवल उदाहरण है कि आप * एक्सपेन्डेबल ऑब्जेक्ट क्लास का उपयोग कैसे करेंगे। अंतर: आलस्य शुरू करें जहां आप * 'एक्सपेन्डेबल ऑब्जेक्ट' (सरल) का उपयोग करते हैं, या 'एक्सपेन्डेबल ऑब्जेक्ट' * स्वयं * (थोड़ा अधिक जटिल) में आलस्य पेश करते हैं। – molf

+1

@molf: जब भी आप 'method_missing' ओवरराइड करते हैं, तो आपको * answer_to?' (या अधिमानतः 'answer_to_missing?' में 1.9.2 ओवरराइड करना होगा)। Http://blog.marc-andre.ca/2010/11/methodmissing-politely.html देखें – Nemo157

5

आप, 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 ऑब्जेक्ट को तुरंत चालू करते हैं जिसमें प्रो में कुछ महंगी वस्तु बनाने के निर्देश दिए गए हैं। यदि आप प्रॉक्सी ऑब्जेक्ट पर कुछ विधि कॉल करते हैं, तो यह पहले महंगी ऑब्जेक्ट को तुरंत चालू करता है और उसके बाद विधि कॉल को प्रतिनिधि करता है।