Ruby Language
Classe Singleton
Recherche…
Syntaxe
- singleton_class = class << objet; fin de soi
Remarques
Les classes singleton n'ont qu'une seule instance: leur objet correspondant. Cela peut être vérifié en interrogeant le ObjectSpace
de Ruby:
instances = ObjectSpace.each_object object.singleton_class
instances.count # => 1
instances.include? object # => true
En utilisant <
, ils peuvent également être vérifiés pour être des sous-classes de la classe réelle de l'objet:
object.singleton_class < object.class # => true
Les références:
introduction
Ruby a trois types d'objets:
- Classes et modules qui sont des instances de classe Class ou class Module.
- Instances de classes.
- Classes Singleton.
Chaque objet a une classe qui contient ses méthodes:
class Example
end
object = Example.new
object.class # => Example
Example.class # => Class
Class.class # => Class
Les objets eux-mêmes ne peuvent pas contenir de méthodes, seule leur classe le peut. Mais avec les classes singleton, il est possible d'ajouter des méthodes à n'importe quel objet, y compris d'autres classes singleton.
def object.foo
:foo
end
object.foo #=> :foo
foo
est défini sur la classe singleton de l' object
. Autres Example
exemples ne peuvent pas répondre à foo
.
Ruby crée des classes singleton à la demande. Leur accès ou leur ajout de méthodes force Ruby à les créer.
Accéder à la classe Singleton
Il y a deux façons d'obtenir la classe singleton d'un objet
- Méthode
singleton_class
. - Réouverture de la classe singleton d'un objet et retour
self
.
object.singleton_class
singleton_class = class << object
self
end
Accès aux variables d'instance / classe dans les classes Singleton
Les classes Singleton partagent leurs variables d'instance / classe avec leur objet.
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
Les blocs se rapprochent de la cible de leurs variables instance / classe. L'accès aux variables d'instance ou de classe à l'aide d'un bloc dans class_eval
ou instance_eval
n'est pas possible. Passer une chaîne à class_eval
ou utiliser class_variable_get
fonctionne autour du problème.
class Foo
@@foo = :foo
end
class Example
@@foo = :example
Foo.define_singleton_method :foo do
@@foo
end
end
Foo.foo #=> :example
Héritage de la classe Singleton
Le sous-classement comprend également les sous-classes de la classe Singleton
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'extension ou l'inclusion d'un module n'élargit pas la classe Singleton
module ExampleModule
end
def ExampleModule.foo
:foo
end
class Example
extend ExampleModule
include ExampleModule
end
Example.foo #=> NoMethodError: undefined method
Propagation des messages avec la classe Singleton
Les instances ne contiennent jamais une méthode qu'elles ne transportent que des données. Cependant, nous pouvons définir une classe singleton pour tout objet incluant une instance d'une classe.
Lorsqu'un message est transmis à un objet (la méthode est appelée), Ruby vérifie tout d'abord si une classe singleton est définie pour cet objet et si elle peut répondre à ce message, sinon Ruby vérifie la chaîne des ancêtres de la classe
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
Réouverture (correction de singe) Classes Singleton
Il existe trois façons de rouvrir une classe Singleton
- Utiliser
class_eval
sur une classe singleton. - Utilisation de la
class <<
block - Utilisation de
def
pour définir une méthode directement sur la classe singleton de l'objet
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
Chaque objet a une classe singleton à laquelle vous pouvez accéder
class Example
end
ex1 = Example.new
def ex1.foobar
:foobar
end
ex1.foobar #=> :foobar
ex2 = Example.new
ex2.foobar #=> NoMethodError
Classes Singleton
Tous les objets sont des instances d'une classe. Cependant, ce n'est pas toute la vérité. Dans Ruby, chaque objet a également une classe singleton quelque peu cachée.
C'est ce qui permet de définir des méthodes sur des objets individuels. La classe singleton se situe entre l'objet lui-même et sa classe réelle, de sorte que toutes les méthodes définies sur cet objet sont disponibles pour cet objet, et cet objet uniquement.
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'exemple ci-dessus aurait pu être écrit en utilisant define_singleton_method
:
object.define_singleton_method :exclusive_method do
"The method is actually defined in the object's singleton class"
end
Ce qui revient à définir la méthode sur 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
Avant l'existence de singleton_class
dans le cadre de l'API principale de Ruby, les classes singleton étaient connues sous le nom de métaclasses et pouvaient être accédées via l'idiome suivant:
class << object
self # refers to object's singleton_class
end