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


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow