Chính xác thì lớp singleton trong ruby ​​là gì?


85

Lớp singleton trong Ruby có phải là lớp trong và của chính nó không? Nó có phải là lý do tại sao tất cả các đối tượng thuộc về "lớp?" Khái niệm này hơi mờ , nhưng tôi tin rằng nó có liên quan đến lý do tại sao tôi có thể định nghĩa một phương thức lớp nào đó ( class foo; def foo.bar ...).

Lớp singleton trong Ruby là gì?

Câu trả lời:


154

Đầu tiên, định nghĩa một chút: phương thức singleton là phương thức chỉ được định nghĩa cho một đối tượng duy nhất. Thí dụ:

irb(main):001:0> class Foo; def method1; puts 1; end; end
=> nil
irb(main):002:0> foo = Foo.new
=> #<Foo:0xb79fa724>
irb(main):003:0> def foo.method2; puts 2; end
=> nil
irb(main):004:0> foo.method1
1
=> nil
irb(main):005:0> foo.method2
2
=> nil
irb(main):006:0> other_foo = Foo.new
=> #<Foo:0xb79f0ef4>
irb(main):007:0> other_foo.method1
1
=> nil
irb(main):008:0> other_foo.method2
NoMethodError: undefined method `method2' for #<Foo:0xb79f0ef4>
        from (irb):8

Phương thức thể hiện là phương thức của một lớp (nghĩa là được định nghĩa trong định nghĩa của lớp). Phương thức lớp là các phương thức đơn lẻ trên Classthể hiện của một lớp - chúng không được định nghĩa trong định nghĩa của lớp. Thay vào đó, chúng được định nghĩa trên lớp singleton của đối tượng.

irb(main):009:0> Foo.method_defined? :method1
=> true
irb(main):010:0> Foo.method_defined? :method2
=> false

Bạn mở lớp singleton của một đối tượng bằng cú pháp class << obj. Ở đây, chúng ta thấy rằng lớp singleton này là nơi các phương thức singleton được định nghĩa:

irb(main):012:0> singleton_class = ( class << foo; self; end )
=> #<Class:#<Foo:0xb79fa724>>
irb(main):013:0> singleton_class.method_defined? :method1
=> true
irb(main):014:0> singleton_class.method_defined? :method2
=> true
irb(main):015:0> other_singleton_class = ( class << other_foo; self; end )
=> #<Class:#<Foo:0xb79f0ef4>>
irb(main):016:0> other_singleton_class.method_defined? :method1
=> true
irb(main):017:0> other_singleton_class.method_defined? :method2
=> false

Vì vậy, một phương tiện thay thế để thêm các phương thức singleton vào một đối tượng sẽ là xác định chúng với lớp singleton của đối tượng đang mở:

irb(main):018:0> class << foo; def method3; puts 3; end; end
=> nil
irb(main):019:0> foo.method3
3
=> nil
irb(main):022:0> Foo.method_defined? :method3
=> false

Tóm tắt:

  • các phương thức phải luôn thuộc về một lớp (hoặc: là các phương thức thể hiện của một số lớp)
  • các phương thức bình thường thuộc về lớp mà chúng được định nghĩa (tức là các phương thức thể hiện của lớp)
  • các phương thức lớp chỉ là các phương thức singleton của một Class
  • các phương thức singleton của một đối tượng không phải là các phương thức thể hiện của lớp đối tượng; đúng hơn, chúng là các phương thức thể hiện của lớp singleton của đối tượng.

17
Trên Headstone của tôi, nó sẽ nói "RIP Ruby Singleton. Pistos đã cứu tôi tỉnh táo."
rmcsharry

1
@sawa Tôi đánh giá cao mục đích chỉnh sửa của bạn, nhưng tôi cảm thấy rằng chúng thay đổi ý nghĩa và cách truyền đạt bài đăng của tôi hơi quá, vì vậy tôi đã lùi các chỉnh sửa của bạn lại.
Pistos

33

Ruby cung cấp một cách để xác định các phương thức dành riêng cho một đối tượng cụ thể và các phương thức đó được gọi là Phương thức Singleton. Khi một người khai báo một phương thức singleton trên một đối tượng, Ruby sẽ tự động tạo một lớp để chỉ chứa các phương thức singleton. Lớp mới tạo được gọi là Lớp Singleton.


    foo = Array.new
    def foo.size
      "Hello World!"
    end
    foo.size  # => "Hello World!"
    foo.class # => Array
    #Create another instance of Array Class and call size method on it
    bar = Array.new
    bar.size  # => 0
Lớp Singleton là lớp ẩn danh đối tượng cụ thể được tạo tự động và chèn vào hệ thống phân cấp kế thừa.

singleton_methods có thể được gọi trên một đối tượng để lấy danh sách tên cho tất cả các phương thức singleton trên một đối tượng.

    foo.singleton_methods  # => [:size]
    bar.singleton_methods  # => []

Bài viết này thực sự đã giúp tôi hiểu các Lớp Singleton trong Ruby và nó có một ví dụ mã tốt.


4
Mặc dù câu trả lời này đã hơn một năm và liên kết hữu ích, nhưng sẽ tốt hơn nếu bạn đăng các phần quan trọng của câu trả lời ở đây, trên trang web này, hoặc bài đăng của bạn có nguy cơ bị xóa. Xem Câu hỏi thường gặp trong đó đề cập đến các câu trả lời 'hầu như không nhiều hơn hơn một liên kết '. Bạn vẫn có thể bao gồm liên kết nếu muốn, nhưng chỉ như một 'tài liệu tham khảo'. Câu trả lời sẽ tự đứng mà không cần liên kết.
Taryn

đồng ý với @bluefeet ở đây
Saurabh

Cảm ơn @bluefeet, đã cập nhật câu trả lời để giải quyết bình luận của bạn.
Bedasso

7

Chỉ cần cập nhật lên câu trả lời @Pistos, từ phiên bản 1.9.2 ruby ​​thêm cú pháp mới để nhận lớp singleton

 singleton_class = ( class << foo; self; end )

có thể được thay thế bằng:

singleton_class = foo.singleton_class

https://apidock.com/ruby/Object/singleton_class


4

Cách thực dụng nhất / hành động để nghĩ về nó (IMHO) là: như một chuỗi kế thừa, hoặc thứ tự tra cứu / phân giải phương thức. Hình ảnh này có thể giúp ích

http://www.klankboomklang.com/2007/11/25/modules-part-i-enter-the-include-class/

Đây là phiên bản r 1.9, nội trang tương phản và các lớp do người dùng xác định: tôi vẫn đang nghiên cứu cái này.

http://d.hatena.ne.jp/sumim/20080111/p1

Ngoài ra, tôi cảm thấy một cách sử dụng khó hiểu của thuật ngữ là "đối tượng Singleton", đó là một khái niệm khác. Một đối tượng singleton đến từ một lớp có phương thức khởi tạo / trình tạo của nó được ghi đè để bạn chỉ có thể cấp phát một trong số lớp đó.


Một trong những liên kết đã chết. Và cái còn lại là tiếng Nhật!
Ulysse BN

0

Một lớp singleton trong các thuật ngữ đơn giản nhất là một lớp đặc biệt ruby ​​hỗ trợ các phương thức lưu trữ được xác định trên các đối tượng riêng lẻ. Trong ruby, có thể xác định các phương thức trên các đối tượng riêng lẻ là duy nhất cho riêng đối tượng đó. Ví dụ, hãy xem xét những điều sau đây

class User; end
user = User.new
def user.age
  "i'm a unique method"
end
user1 = User.new 
user.age #"i'm a unique method"
user1.age # NoMethodError (undefined method `age' for #<User:0x0000559c66ab7338>)

Như bạn có thể thấy ở trên, đối tượng user1 không phản hồi phương thức 'age' vì nó là một phương thức singleton, một phương thức được định nghĩa duy nhất trên đối tượng người dùng. Để điều này xảy ra, ruby ​​tạo ra một lớp đặc biệt, được gọi là lớp singleton, hoặc lớp eigenclass, để lưu trữ phương thức duy nhất này. Bạn có thể xác minh điều này bằng cách làm như sau:

user.singleton_class # #<Class:#<User:0x0000559c66b47c58>>

Bạn cũng có thể hỏi ruby ​​xem phương thức 'age' có được tìm thấy ở đây hay không bằng cách sử dụng đối tượng method để tìm nơi phương thức 'age' được xác định. Khi bạn làm điều này, bạn sẽ thấy rằng lớp singleton có phương thức đó.

user_singleton_class = user.method(:age).owner # #<Class:#<User:0x0000559c66b47c58>>
user.method(:age).owner == user.singleton_class # true
user_singleton_class.instance_methods(false) # [:age]

Cũng lưu ý rằng, đối với một lớp singleton, các phương thức singleton thực sự là phương thức thể hiện của nó.

user.singleton_methods == user_singleton_class.instance_methods(false) # true
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.