Ruby Language
Singleton klass
Sök…
Syntax
- singleton_class = klass << objekt; själv slut
Anmärkningar
Singleton-klasser har bara en instans: deras motsvarande objekt. Detta kan verifieras genom att fråga Ruby's ObjectSpace
:
instances = ObjectSpace.each_object object.singleton_class
instances.count # => 1
instances.include? object # => true
Med hjälp av <
kan de också verifieras till att vara underklasser av objektets faktiska klass:
object.singleton_class < object.class # => true
referenser:
Introduktion
Ruby har tre typer av objekt:
- Klasser och moduler som är fall av klass Klass eller klassmodul.
- Instanser av klasser.
- Singleton klasser.
Varje objekt har en klass som innehåller dess metoder:
class Example
end
object = Example.new
object.class # => Example
Example.class # => Class
Class.class # => Class
Objekt själva kan inte innehålla metoder, bara deras klass kan. Men med singleton klasser är det möjligt att lägga till metoder till alla objekt inklusive andra singleton klasser.
def object.foo
:foo
end
object.foo #=> :foo
foo
definieras på singleton klass av object
. Andra Example
instanser kan inte svara på foo
.
Ruby skapar singleton-klasser på begäran. Att komma åt dem eller lägga till metoder till dem tvingar Ruby att skapa dem.
Åtkomst till Singleton Class
Det finns två sätt att få en klass av ett objekt
-
singleton_class
metod. - Återöppna singleton klass av ett objekt och återvända
self
.
object.singleton_class
singleton_class = class << object
self
end
Få åtkomst till instans- / klassvariabler i Singleton-klasser
Singleton-klasser delar sina instanser / klassvariabler med sitt objekt.
class Example
@@foo = :example
end
def Example.foo
class_variable_get :@@foo
end
Example.foo #=> :example
class Example
def initialize
@foo = 1
end
def foo
@foo
end
end
e = Example.new
e.instance_eval <<-BLOCK
def self.increase_foo
@foo += 1
end
BLOCK
e.increase_foo
e.foo #=> 2
Block stänger runt deras instans / klassvariabler. Åtkomst instans eller klassvariabler med hjälp av ett block i class_eval
eller instance_eval
är inte möjlig. Att class_eval
en sträng till class_eval
eller använda class_variable_get
fungerar kring problemet.
class Foo
@@foo = :foo
end
class Example
@@foo = :example
Foo.define_singleton_method :foo do
@@foo
end
end
Foo.foo #=> :example
Inheritance of Singleton Class
Subclasses också Subclasses Singleton Class
class Example
end
Example.singleton_class #=> #<Class:Example>
def Example.foo
:example
end
class SubExample < Example
end
SubExample.foo #=> :example
SubExample.singleton_class.superclass #=> #<Class:Example>
Att utvidga eller inkludera en modul förlänger inte Singleton Class
module ExampleModule
end
def ExampleModule.foo
:foo
end
class Example
extend ExampleModule
include ExampleModule
end
Example.foo #=> NoMethodError: undefined method
Meddelandeförökning med Singleton Class
Instanser innehåller aldrig en metod som de bara bär data. Men vi kan definiera en singleton klass för alla objekt inklusive en instans av en klass.
När ett meddelande skickas till ett objekt (metod kallas) kontrollerar Ruby först om en singleton-klass är definierad för det objektet och om det kan svara på det meddelandet annars kontrollerar Ruby instans klassens förfäder kedja och går upp på det.
class Example
def foo
:example
end
end
Example.new.foo #=> :example
module PrependedModule
def foo
:prepend
end
end
class Example
prepend PrependedModule
end
Example.ancestors #=> [Prepended, Example, Object, Kernel, BasicObject]
e = Example.new
e.foo #=> :prepended
def e.foo
:singleton
end
e.foo #=> :singleton
Återöppning (monkey patch) Singleton klasser
Det finns tre sätt att öppna en Singleton Class igen
- Använda
class_eval
på en singleton klass. - Med hjälp av
class <<
block. - Använd
def
att definiera en metod direkt i objektets singleton-klass
class Example
end
Example.singleton_class.class_eval do
def foo
:foo
end
end
Example.foo #=> :foo
class Example
end
class << Example
def bar
:bar
end
end
Example.bar #=> :bar
class Example
end
def Example.baz
:baz
end
Example.baz #=> :baz
Varje objekt har en singleton-klass som du kan komma åt
class Example
end
ex1 = Example.new
def ex1.foobar
:foobar
end
ex1.foobar #=> :foobar
ex2 = Example.new
ex2.foobar #=> NoMethodError
Singleton klasser
Alla objekt är instanser av en klass. Men det är inte hela sanningen. I Ruby har varje objekt också en något dold singletonklass .
Det är detta som gör det möjligt att definiera metoder på enskilda objekt. Singleton-klassen sitter mellan själva objektet och dess faktiska klass, så alla metoder som definieras på det är tillgängliga för det objektet och endast det objektet.
object = Object.new
def object.exclusive_method
'Only this object will respond to this method'
end
object.exclusive_method
# => "Only this object will respond to this method"
Object.new.exclusive_method rescue $!
# => #<NoMethodError: undefined method `exclusive_method' for #<Object:0xa17b77c>>
Exemplet ovan kunde ha skrivits med define_singleton_method
:
object.define_singleton_method :exclusive_method do
"The method is actually defined in the object's singleton class"
end
Vilket är detsamma som att definiera metoden på object
singleton_class
:
# send is used because define_method is private
object.singleton_class.send :define_method, :exclusive_method do
"Now we're defining an instance method directly on the singleton class"
end
Innan singleton_class
som en del av Rubys kärn-API, var singleton-klasser kända som metaclasses och kunde nås via följande formspråk:
class << object
self # refers to object's singleton_class
end