21

Rubyの場合、オブジェクトの作成が必要になる可能性がありますが、よくわかりません。また、オブジェクトの作成にはコストがかかる可能性があるため、私はオブジェクトの作成にあまり熱心ではありません。これは遅延読み込みの明確なケースだと思います。誰かがメッセージを送信したときにのみ作成されないオブジェクトを定義するにはどうすればよいですか?オブジェクトはブロック内に作成されます。Rubyで単純な遅延読み込み/初期化を行う方法はありますか?これらのものは、オブジェクトの遅延初期化のさまざまなケースに異なるソリューションを提供するいくつかの宝石によってサポートされていますか?あなたの提案をありがとう!

4

2 に答える 2

40

2つの方法があります。

1つは、呼び出し元に遅延オブジェクトの作成を処理させることです。これは最も単純なソリューションであり、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

2番目のオプションは、オブジェクトがそれ自体を遅延的に初期化するようにすることです。これを実現するために、実際のオブジェクトの周囲にデリゲートオブジェクトを作成します。このアプローチはもう少し注意が必要で、たとえば、変更できない既存の呼び出しコードがない限り、お勧めできません。

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

stdlibdelegateを使用して、これを上に構築することもできます。

于 2010-03-17T10:51:46.767 に答える
7

コードの断片を遅延評価したい場合は、プロキシを使用します。

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

それはどのように機能しますか?Proc で高価なオブジェクトを構築する方法についての指示を保持する LazyProxy オブジェクトをインスタンス化します。その後、プロキシ オブジェクトで何らかのメソッドを呼び出すと、最初に高価なオブジェクトがインスタンス化され、次にメソッド呼び出しが委任されます。

于 2010-03-17T13:50:06.087 に答える