Le Singleton est un patron de conception de création qui s’assure de l’existence d’un seul objet de son genre et fournit un unique point d’accès vers cet objet.
Le singleton possède à peu près les mêmes avantages et inconvénients que les variables globales. Même s’ils sont super utiles, ils réduisent la modularité du code.
Vous ne pourrez pas utiliser une classe qui dépend d’un singleton dans un autre contexte. Vous devrez également inclure complètement la classe Singleton dans votre code. En général, on se rend compte de cette limitation lorsque l’on crée des tests unitaires.
Exemples d’utilisation : Beaucoup de développeurs considèrent que le singleton est un antipatron. C’est pourquoi il est de moins en moins utilisé en Ruby.
Identification : Le singleton peut être reconnu par une méthode de création statique qui retourne le même objet en cache.
Singleton naïf
Il est très facile d’implémenter un singleton bâclé. Il suffit de cacher le constructeur et d’implémenter une méthode de création statique.
Cette même classe peut mal fonctionner dans un environnement multithread. Plusieurs threads vont pouvoir appeler la méthode de création simultanément et créer plusieurs instances de la classe Singleton.
main.rb: Exemple conceptuel
# The Singleton class defines the `instance` method that lets clients access the # unique singleton instance. class Singleton @instance = new private_class_method :new # The static method that controls the access to the singleton instance. # # This implementation let you subclass the Singleton class while keeping just # one instance of each subclass around. def self.instance @instance end # Finally, any singleton should define some business logic, which can be # executed on its instance. def some_business_logic # ... end end # The client code. s1 = Singleton.instance s2 = Singleton.instance if s1.equal?(s2) print 'Singleton works, both variables contain the same instance.' else print 'Singleton failed, variables contain different instances.' end
output.txt: Résultat de l’exécution
Singleton works, both variables contain the same instance.
Singleton thread-safe
Pour régler ce problème, vous devez synchroniser les threads lors de la première création de l’objet Singleton.
main.rb: Exemple conceptuel
# The Singleton class defines the `instance` method that lets clients access the # unique singleton instance. class Singleton attr_reader :value @instance_mutex = Mutex.new private_class_method :new def initialize(value) @value = value end # The static method that controls the access to the singleton instance. # # This implementation let you subclass the Singleton class while keeping just # one instance of each subclass around. def self.instance(value) return @instance if @instance @instance_mutex.synchronize do @instance ||= new(value) end @instance end # Finally, any singleton should define some business logic, which can be # executed on its instance. def some_business_logic # ... end end # @param [String] value def test_singleton(value) singleton = Singleton.instance(value) puts singleton.value end # The client code. puts "If you see the same value, then singleton was reused (yay!)\n"\ "If you see different values, then 2 singletons were created (booo!!)\n\n"\ "RESULT:\n\n" process1 = Thread.new { test_singleton('FOO') } process2 = Thread.new { test_singleton('BAR') } process1.join process2.join
output.txt: Résultat de l’exécution
If you see the same value, then singleton was reused (yay!) If you see different values, then 2 singletons were created (booo!!) RESULT: FOO FOO