ventajas tecnicas programacion perezosa funcional evaluacion desventajas con ruby lazy-loading lazy-evaluation

ruby - tecnicas - programacion funcional ventajas y desventajas



Evaluación perezosa en rubí (2)

Hay dos maneras.

La primera es dejar que el llamador maneje la creación de objetos perezosos. Esta es la solución más simple, y es un patrón muy común en el código Ruby.

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

La segunda opción es dejar que el objeto se inicialice perezosamente. Creamos un objeto delegado alrededor de nuestro objeto real para lograr esto. Este enfoque es un poco más complicado y no se recomienda a menos que tenga un código de llamada existente que no pueda modificar, por ejemplo.

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

También puede utilizar el delegate stdlib para construir esto sobre.

Tengo una situación para Ruby, donde es posible que sea necesario crear un objeto, pero no es seguro. Y como la creación del objeto puede ser costosa, no estoy demasiado ansioso por crearlo. Creo que este es un caso claro para la carga perezosa. ¿Cómo puedo definir un objeto que no se crea solo cuando alguien le envía un mensaje? El objeto sería creado en un bloque. ¿Hay alguna forma de carga / inicialización perezosa simple en Ruby? ¿Están estas cosas respaldadas por algunas gemas, que proporcionan diferentes soluciones para varios casos de inicialización perezosa de objetos? Gracias por tus sugerencias!


Si desea evaluar partes de código con pereza, use un proxy:

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

Entonces lo usas así:

expensive_object = LazyProxy.new { ExpensiveObject.new } expensive_object.do_something

Puedes usar este código para hacer una inicialización arbitrariamente compleja de cosas caras:

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

¿Como funciona? Usted crea una instancia de un objeto LazyProxy que contiene instrucciones sobre cómo construir un objeto costoso en un Proc. Si luego llama a algún método en el objeto proxy, primero crea una instancia del objeto costoso y luego le delega la llamada al método.