Ruby Language
Singleton Class
Ricerca…
Sintassi
- singleton_class = class << object; fine di sé
Osservazioni
Le classi Singleton hanno solo un'istanza: il loro oggetto corrispondente. Questo può essere verificato interrogando Ruby's ObjectSpace
:
instances = ObjectSpace.each_object object.singleton_class
instances.count # => 1
instances.include? object # => true
Usando <
, possono anche essere verificate come sottoclassi della classe effettiva dell'oggetto:
object.singleton_class < object.class # => true
Riferimenti:
introduzione
Ruby ha tre tipi di oggetti:
- Classi e moduli che sono istanze di classe Classe o modulo di classe.
- Istanze di classi
- Singleton Classes.
Ogni oggetto ha una classe che contiene i suoi metodi:
class Example
end
object = Example.new
object.class # => Example
Example.class # => Class
Class.class # => Class
Gli oggetti stessi non possono contenere metodi, solo la loro classe può. Ma con le classi singleton, è possibile aggiungere metodi a qualsiasi oggetto incluse altre classi di singleton.
def object.foo
:foo
end
object.foo #=> :foo
foo
è definito sulla classe di object
singleton. Altri Example
casi non possono rispondere a foo
.
Ruby crea corsi singoli su richiesta. Accedervi o aggiungere metodi a loro forza costringe Ruby a crearli.
Accesso alla classe Singleton
Esistono due modi per ottenere la classe singleton di un oggetto
- metodo
singleton_class
. - Riapertura della classe singleton di un oggetto e ritorno di
self
.
object.singleton_class
singleton_class = class << object
self
end
Accesso alle variabili istanza / classe nelle classi Singleton
Le classi Singleton condividono le loro istanze / variabili di classe con il loro oggetto.
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
I blocchi si chiudono attorno alla loro variabile di istanza / classe target. Non è possibile accedere alle variabili di istanza o classe utilizzando un blocco in class_eval
o instance_eval
. Passare una stringa a class_eval
o utilizzare class_variable_get
il problema.
class Foo
@@foo = :foo
end
class Example
@@foo = :example
Foo.define_singleton_method :foo do
@@foo
end
end
Foo.foo #=> :example
Eredità della classe Singleton
Sottoclassi anche sottoclassi 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>
L'estensione o l'inclusione di un modulo non estende la classe Singleton
module ExampleModule
end
def ExampleModule.foo
:foo
end
class Example
extend ExampleModule
include ExampleModule
end
Example.foo #=> NoMethodError: undefined method
Propagazione dei messaggi con la classe Singleton
Le istanze non contengono mai un metodo che portano solo dati. Tuttavia possiamo definire una classe singleton per qualsiasi oggetto che includa un'istanza di una classe.
Quando un messaggio viene passato a un oggetto (il metodo viene chiamato) Ruby controlla prima se una classe singleton è definita per quell'oggetto e se può rispondere a quel messaggio altrimenti Ruby verifica la catena di antenati della classe dell'istanza e ne va su.
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
Riapertura (scimmia rattoppando) Singleton Classes
Esistono tre modi per riaprire una classe Singleton
- Usando
class_eval
su una classe singleton. - Usando il
class <<
block. - Utilizzando
def
per definire direttamente un metodo sulla classe Singleton dell'oggetto
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
Ogni oggetto ha una classe singleton a cui è possibile accedere
class Example
end
ex1 = Example.new
def ex1.foobar
:foobar
end
ex1.foobar #=> :foobar
ex2 = Example.new
ex2.foobar #=> NoMethodError
Lezioni di Singleton
Tutti gli oggetti sono istanze di una classe. Tuttavia, non è tutta la verità. In Ruby, ogni oggetto ha anche una classe singleton un po 'nascosta.
Questo è ciò che consente di definire i metodi su singoli oggetti. La classe singleton si trova tra l'oggetto stesso e la sua classe effettiva, quindi tutti i metodi definiti su di esso sono disponibili per quell'oggetto e solo quell'oggetto.
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>>
L'esempio precedente potrebbe essere stato scritto usando define_singleton_method
:
object.define_singleton_method :exclusive_method do
"The method is actually defined in the object's singleton class"
end
Il che equivale a definire il metodo sulla singleton_class
object
:
# 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
Prima dell'esistenza di singleton_class
come parte dell'API core di Ruby, le classi singleton erano conosciute come metaclassi e potevano essere accessibili tramite il seguente idioma:
class << object
self # refers to object's singleton_class
end