คลาสซิงเกิลในทับทิมคืออะไร?


85

คลาสซิงเกิลใน Ruby เป็นคลาสในตัวเองหรือไม่? มันเป็นเหตุผลว่าทำไมวัตถุทั้งหมดเป็นของ "คลาส"? แนวคิดนั้นคลุมเครือแต่ฉันเชื่อว่ามันมีส่วนเกี่ยวข้องกับสาเหตุที่ฉันสามารถกำหนดเมธอดคลาสได้เลย ( class foo; def foo.bar ...)

คลาส Singleton ใน Ruby คืออะไร?

คำตอบ:


154

ประการแรกคำจำกัดความเล็กน้อย: วิธีเดี่ยวคือวิธีการที่กำหนดไว้สำหรับวัตถุเดียวเท่านั้น ตัวอย่าง:

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

วิธีการอินสแตนซ์เป็นวิธีการของคลาส (กล่าวคือกำหนดไว้ในนิยามของคลาส) เมธอดคลาสคือเมธอดเดี่ยวบนClassอินสแตนซ์ของคลาส - ไม่ได้กำหนดไว้ในนิยามของคลาส แต่ถูกกำหนดไว้ในคลาสซิงเกิลตันของอ็อบเจ็กต์

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

class << objคุณสามารถเปิดชั้นเดี่ยวของวัตถุที่มีไวยากรณ์ ที่นี่เราจะเห็นว่าคลาสซิงเกิลตันนี้เป็นที่ที่กำหนดเมธอด singleton:

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

ดังนั้นวิธีการอื่นในการเพิ่มวิธีการ singleton ให้กับวัตถุคือการกำหนดด้วยคลาส singleton ของวัตถุที่เปิดอยู่

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

สรุป:

  • เมธอดต้องเป็นของคลาสเสมอ (หรือเป็นเช่นเมธอดของคลาสบางคลาส)
  • เมธอดปกติเป็นของคลาสที่กำหนดไว้ (เช่นเป็นวิธีการอินสแตนซ์ของคลาส)
  • วิธีการเรียนเป็นเพียงวิธีเดี่ยวของ Class
  • วิธีการเดี่ยวของวัตถุไม่ใช่วิธีการตัวอย่างของคลาสของวัตถุ แต่เป็นวิธีการอินสแตนซ์ของคลาสซิงเกิลตันของอ็อบเจ็กต์

17
บนศิลาฤกษ์ของฉันจะมีข้อความว่า "RIP Ruby Singleton Pistos ช่วยรักษาสติของฉัน"
rmcsharry

1
@sawa ขอขอบคุณในความตั้งใจในการแก้ไขของคุณ แต่ฉันรู้สึกว่าพวกเขาเปลี่ยนความหมายและการสื่อสารของโพสต์ของฉันมากเกินไปฉันจึงได้ยกเลิกการแก้ไขของคุณแล้ว
Pistos

33

Ruby ให้วิธีการกำหนดวิธีการที่เฉพาะเจาะจงสำหรับวัตถุเฉพาะและวิธีการดังกล่าวเรียกว่า Singleton Methods เมื่อคนหนึ่งประกาศเมธอด singleton บนวัตถุ Ruby จะสร้างคลาสโดยอัตโนมัติเพื่อเก็บเฉพาะเมธอด singleton คลาสที่สร้างขึ้นใหม่เรียกว่าคลาส 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
คลาส Singleton เป็นคลาสที่ไม่ระบุชื่อเฉพาะของออบเจ็กต์ที่สร้างขึ้นโดยอัตโนมัติและแทรกลงในลำดับชั้นการสืบทอด

singleton_methods สามารถเรียกบนอ็อบเจกต์เพื่อรับรายชื่อของเมธอด singleton ทั้งหมดบนอ็อบเจ็กต์

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

นี้บทความจริงๆช่วยให้ฉันเข้าใจเรียนซิงเกิลในรูบีและมีโค้ดตัวอย่างที่ดี


4
แม้ว่าคำตอบนี้จะมีอายุมากกว่าหนึ่งปีและลิงก์นี้จะมีประโยชน์ แต่มันจะดีกว่าถ้าคุณโพสต์ส่วนสำคัญของคำตอบที่นี่บนเว็บไซต์นี้หรือโพสต์ของคุณมีความเสี่ยงที่จะถูกลบดูคำถามที่พบบ่อยซึ่งกล่าวถึงคำตอบที่ 'แทบจะไม่มากขึ้น กว่าลิงค์ '. คุณยังสามารถใส่ลิงก์ได้หากต้องการ แต่เป็นเพียง "ข้อมูลอ้างอิง" เท่านั้น คำตอบควรอยู่ในตัวเองโดยไม่ต้องใช้ลิงก์
Taryn

เห็นด้วยกับ @bluefeet ที่นี่
Saurabh

ขอบคุณ @bluefeet อัปเดตคำตอบเพื่อแสดงความคิดเห็นของคุณ
Bedasso

7

เช่นเดียวกับการอัปเดตเป็นคำตอบ @Pistos จากเวอร์ชัน 1.9.2 Ruby จะเพิ่มไวยากรณ์ใหม่ไปจนถึงการรับคลาสซิงเกิลตัน

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

สามารถแทนที่ได้ด้วย:

singleton_class = foo.singleton_class

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


4

วิธีคิดเชิงปฏิบัติ / การกระทำที่เป็นประโยชน์มากที่สุดในการคิด (IMHO) คือ: เป็นห่วงโซ่การสืบทอดหรือลำดับการค้นหาวิธีการ / การแก้ไข ภาพนี้อาจช่วยได้

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

นี่คือ r 1.9 ซึ่งแตกต่างจากคลาสในตัวและคลาสที่ผู้ใช้กำหนดเอง: ฉันยังย่อยอันนี้อยู่

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

นอกจากนี้ฉันคิดว่าการใช้คำที่สับสนคือ "Singleton object" ซึ่งเป็นแนวคิดที่แตกต่างกัน อ็อบเจ็กต์ singleton มาจากคลาสที่มีตัวสร้าง / วิธีการสร้างอินสแตนซ์แทนเพื่อให้คุณสามารถจัดสรรคลาสนั้นได้


ลิงค์ใดลิงค์หนึ่งตายไปแล้ว และอีกคนเป็นคนญี่ปุ่น!
Ulysse BN

0

คลาสซิงเกิลตันในคำที่ง่ายที่สุดคือทับทิมคลาสพิเศษแส้ขึ้นกับเมธอดโฮสต์ที่กำหนดไว้ในแต่ละออบเจ็กต์ ในทับทิมเป็นไปได้ที่จะกำหนดวิธีการบนวัตถุแต่ละชิ้นที่มีลักษณะเฉพาะสำหรับวัตถุนั้นเพียงอย่างเดียว ตัวอย่างเช่นพิจารณาสิ่งต่อไปนี้ด้านล่าง

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>)

ดังที่คุณเห็นด้านบนอ็อบเจ็กต์ user1 ไม่ตอบสนองต่อเมธอด 'age' เนื่องจากเป็นเมธอดเดี่ยวซึ่งเป็นวิธีการที่กำหนดโดยไม่ซ้ำกันบนอ็อบเจ็กต์ผู้ใช้ เพื่อให้สิ่งนี้เกิดขึ้น Ruby จึงสร้างคลาสพิเศษที่เรียกว่าคลาส singleton หรือ eigenclass เพื่อโฮสต์วิธีการเฉพาะนี้ คุณสามารถตรวจสอบได้โดยดำเนินการดังต่อไปนี้:

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

คุณยังสามารถถามทับทิมว่าพบเมธอด 'age' ที่นี่หรือไม่โดยใช้ method object เพื่อค้นหาว่าเมธอด 'age' ถูกกำหนดไว้ที่ใด เมื่อคุณทำสิ่งนี้คุณจะเห็นว่าคลาส singleton มีวิธีการนั้น

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]

โปรดทราบว่าในขณะที่คลาสซิงเกิลตันใช้วิธีการแบบซิงเกิลตันเป็นวิธีอินสแตนซ์

user.singleton_methods == user_singleton_class.instance_methods(false) # true
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.