Tôi có một tình huống đối với Ruby, nơi một đối tượng có thể cần thiết được tạo ra, nhưng nó không chắc chắn. Và như việc tạo ra các đối tượng có thể tốn kém tôi không quá háo hức tạo ra nó. Tôi nghĩ đây là một trường hợp rõ ràng cho việc tải chậm. Làm thế nào tôi có thể xác định một đối tượng mà không được tạo ra chỉ khi ai đó gửi một tin nhắn đến nó? Đối tượng sẽ được tạo trong một khối. Có cách nào để tải/khởi tạo đơn giản trong Ruby? Có phải những thứ này được hỗ trợ bởi một số đá quý, cung cấp các giải pháp khác nhau cho các trường hợp khởi tạo lười biếng của các đối tượng khác nhau không? Cảm ơn lời đề nghị của bạn!Đánh giá lười biếng trong Ruby
Trả lời
Có hai cách.
Đầu tiên là để người gọi gọi xử lý việc tạo đối tượng lười biếng. Đây là giải pháp đơn giản nhất, và nó là mẫu rất phổ biến trong mã 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
Lựa chọn thứ hai là để cho các đối tượng khởi bản thân lười biếng. Chúng tôi tạo ra một đối tượng đại biểu xung quanh đối tượng thực tế của chúng tôi để đạt được điều này. Cách tiếp cận này phức tạp hơn một chút và không được khuyến nghị trừ khi bạn có mã gọi hiện tại mà bạn không thể sửa đổi, ví dụ.
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
Bạn cũng có thể sử dụng stdlib delegate
để tạo điều này trên đầu trang.
Trong ví dụ đầu tiên, tôi cần giữ nguyên thể hiện của lớp Caller. Đúng? Nhưng sự khác biệt đối với tôi là gì - để giữ cho cá thể lớp Caller hoặc giữ cá thể lớp đắt tiền? – demas
Trong ví dụ đầu tiên, lớp 'Caller' chỉ là một ví dụ về cách bạn sẽ sử dụng * lớp ExpensiveObject. Sự khác biệt: giới thiệu sự lười biếng nơi bạn * sử dụng * 'ExpensiveObject' (đơn giản), hoặc giới thiệu sự lười biếng trong chính' ExpensiveObject' * (hơi phức tạp hơn). – molf
@molf: Bất cứ khi nào bạn ghi đè 'method_missing' bạn * phải * cũng ghi đè' respond_to? '(Hoặc tốt hơn là' respond_to_missing? 'Trong 1.9.2). Xem http://blog.marc-andre.ca/2010/11/methodmissing-politely.html – Nemo157
Nếu bạn muốn lười biếng đánh giá từng phần mã, sử dụng 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
Sau đó bạn sử dụng nó như thế này:
expensive_object = LazyProxy.new { ExpensiveObject.new }
expensive_object.do_something
Bạn có thể sử dụng mã này để làm khởi tùy tiện phức tạp của công cụ đắt tiền:
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
Cách hoạt động? Bạn khởi tạo một đối tượng LazyProxy chứa các chỉ dẫn về cách xây dựng một số đối tượng đắt tiền trong một Proc. Nếu sau đó bạn gọi một số phương thức trên đối tượng proxy, nó sẽ khởi tạo đối tượng đắt tiền đầu tiên và sau đó ủy quyền cuộc gọi phương thức cho đối tượng đó.
- 1. Ruby Challenge - Phương pháp chuỗi và đánh giá lười biếng
- 2. Đánh giá lười biếng không tầm thường
- 3. Vấn đề đánh giá lười biếng
- 4. String.format với đánh giá lười biếng
- 5. MATLAB Đánh giá Lười biếng trong Thuộc tính Phụ thuộc
- 6. đánh giá lười biếng với autoload vs yêu cầu trong ruby?
- 7. LINQ có được đánh giá lười biếng không?
- 8. Khi nào việc đánh giá lười biếng không hữu ích?
- 9. Mathematica 7 có hỗ trợ đánh giá lười biếng không?
- 10. C# biểu thức lambda và đánh giá lười biếng
- 11. Giải thích một câu hỏi đánh giá lười biếng
- 12. PHP ngắn mạch đánh giá lười biếng, mà là nó trong hướng dẫn sử dụng php.net?
- 13. Đánh giá lười biếng trong R - được chỉ định bị ảnh hưởng?
- 14. Cần giúp đỡ trong việc hiểu hành vi đánh giá lười biếng của Haskell
- 15. Tại sao không lười biếng
- 16. lười biếng các loại lặp trong Scala?
- 17. Python, danh sách lười biếng
- 18. Bàn điều khiển JavaScript của Chrome có lười biếng về việc đánh giá mảng không?
- 19. Clojure: giới hạn gc overhead vượt quá, đánh giá lười biếng, pi chuỗi
- 20. hGetContents quá lười biếng
- 21. Có thể tải lười biếng cho một mối quan hệ không lười biếng trong Hibernate không?
- 22. Tiêm phụ thuộc lười biếng
- 23. Trình lặp lười biếng của Python
- 24. Ocaml: Danh sách lười biếng
- 25. Thư viện tải lười biếng?
- 26. Tải Lười biếng là gì?
- 27. Clojure: ma thuật lười biếng
- 28. Khởi tạo lười biếng trong .NET 4
- 29. Các trang tải lười biếng trong UIScrollView
- 30. Sản phẩm cartesian lười biếng trong Haskell
Thay vì tự lăn, bạn có thể sử dụng [lazy.rb] (https://github.com/mental/lazy). Có một số ví dụ về cách sử dụng trong sách [Thực hành tốt nhất của Ruby] (http://oreilly.com/catalog/9780596523015/), xem trang 123 và chuyển tiếp. –