Pourquoi le motif Borg est-il meilleur que le motif Singleton ?
Je demande parce que je ne les vois pas aboutir à quelque chose de différent.
Borg:
class Borg:
__shared_state = {}
# init internal state variables here
__register = {}
def __init__(self):
self.__dict__ = self.__shared_state
if not self.__register:
self._init_default_register()
Singleton:
class Singleton:
def __init__(self):
# init internal state variables here
self.__register = {}
self._init_default_register()
# singleton mechanics external to class, for example this in the module
Singleton = Singleton()
Ce que je veux montrer ici, c'est que l'objet de service, qu'il soit implémenté sous Borg ou Singleton, a un état interne non trivial (il fournit un service basé sur celui-ci) (je veux dire qu'il doit être utile, ce n'est pas un Singleton/Borg juste pour amusement).
Et cet état doit être inité. Ici, l’implémentation de Singleton est plus simple, puisque nous traitons init comme la configuration de l’état global. Je trouve gênant que l'objet Borg doive interroger son état interne pour savoir s'il doit se mettre à jour.
Cela devient pire à mesure que votre état interne augmente. Par exemple, si l'objet doit écouter le signal de suppression de l'application pour enregistrer son registre sur un disque, cet enregistrement ne doit être effectué qu'une seule fois, ce qui est plus facile avec un Singleton.
La vraie raison pour laquelle borg est différent se résume à un sous-classement.
Si vous sous-classez un borg, les objets de la sous-classe ont le même état que leurs objets de classes parents, à moins que vous ne remplaciez explicitement l'état partagé dans cette sous-classe. Chaque sous-classe du motif singleton a son propre état et produira donc différents objets.
De plus, dans le motif singleton, les objets sont en réalité les mêmes, pas seulement l'état (même si l'état est la seule chose qui compte vraiment).
En python, si vous voulez un "objet" unique auquel vous pouvez accéder de n'importe où, créez simplement une classe Unique
qui ne contient que des attributs statiques, @staticmethod
s et @classmethod
s; vous pourriez l'appeler le modèle unique. Ici, je mets en œuvre et compare les 3 modèles:
Unique
#Unique Pattern
class Unique:
#Define some static variables here
x = 1
@classmethod
def init(cls):
#Define any computation performed when assigning to a "new" object
return cls
Singleton
#Singleton Pattern
class Singleton:
__single = None
def __init__(self):
if not Singleton.__single:
#Your definitions here
self.x = 1
else:
raise RuntimeError('A Singleton already exists')
@classmethod
def getInstance(cls):
if not cls.__single:
cls.__single = Singleton()
return cls.__single
Borg
#Borg Pattern
class Borg:
__monostate = None
def __init__(self):
if not Borg.__monostate:
Borg.__monostate = self.__dict__
#Your definitions here
self.x = 1
else:
self.__dict__ = Borg.__monostate
Tester
#SINGLETON
print "\nSINGLETON\n"
A = Singleton.getInstance()
B = Singleton.getInstance()
print "At first B.x = {} and A.x = {}".format(B.x,A.x)
A.x = 2
print "After A.x = 2"
print "Now both B.x = {} and A.x = {}\n".format(B.x,A.x)
print "Are A and B the same object? Answer: {}".format(id(A)==id(B))
#BORG
print "\nBORG\n"
A = Borg()
B = Borg()
print "At first B.x = {} and A.x = {}".format(B.x,A.x)
A.x = 2
print "After A.x = 2"
print "Now both B.x = {} and A.x = {}\n".format(B.x,A.x)
print "Are A and B the same object? Answer: {}".format(id(A)==id(B))
#UNIQUE
print "\nUNIQUE\n"
A = Unique.init()
B = Unique.init()
print "At first B.x = {} and A.x = {}".format(B.x,A.x)
A.x = 2
print "After A.x = 2"
print "Now both B.x = {} and A.x = {}\n".format(B.x,A.x)
print "Are A and B the same object? Answer: {}".format(id(A)==id(B))
Sortie:
SINGLETON
At first B.x = 1 and A.x = 1 After A.x = 2 Now both B.x = 2 and A.x = 2 Are A and B the same object? Answer: True BORG At first B.x = 1 and A.x = 1 After A.x = 2 Now both B.x = 2 and A.x = 2 Are A and B the same object? Answer: False UNIQUE At first B.x = 1 and A.x = 1 After A.x = 2 Now both B.x = 2 and A.x = 2 Are A and B the same object? Answer: True
À mon avis, la mise en œuvre unique est la plus facile, puis Borg et enfin Singleton avec un nombre moche de deux fonctions nécessaires à sa définition.
Ce n'est pas. Ce qui n’est généralement pas recommandé est un motif comme celui-ci en python:
class Singleton(object):
_instance = None
def __init__(self, ...):
...
@classmethod
def instance(cls):
if cls._instance is None:
cls._instance = cls(...)
return cls._instance
où vous utilisez une méthode de classe pour obtenir l'instance au lieu du constructeur. La métaprogrammation de Python permet des méthodes bien meilleures, par exemple. celui sur Wikipedia :
class Singleton(type):
def __init__(cls, name, bases, dict):
super(Singleton, cls).__init__(name, bases, dict)
cls.instance = None
def __call__(cls, *args, **kw):
if cls.instance is None:
cls.instance = super(Singleton, cls).__call__(*args, **kw)
return cls.instance
class MyClass(object):
__metaclass__ = Singleton
print MyClass()
print MyClass()
Une classe décrit en gros comment vous pouvez accéder (lire/écrire) à l'état interne de votre objet.
Dans le modèle singleton, vous ne pouvez avoir qu'une seule classe, c'est-à-dire que tous vos objets vous donneront les mêmes points d'accès à l'état partagé . Cela signifie que si vous devez fournir une API étendue, vous devrez écrire un wrapper. , enveloppant le singleton
Dans le modèle borg, vous pouvez étendre la classe de base "borg", et donc plus facilement étendre l’API à votre goût.
Ce n'est que mieux dans les quelques cas où vous avez réellement une différence. Comme quand tu sous-classe. Le motif Borg est extrêmement inhabituel, je n’en ai jamais eu besoin depuis 10 ans en programmation Python.
En outre, le modèle de type Borg permet aux utilisateurs de la classe de choisir s’ils souhaitent partager l’état ou créer une instance distincte. (que cela soit ou non une bonne idée est un sujet séparé)
class MayBeBorg:
__monostate = None
def __init__(self, shared_state=True, ..):
if shared_state:
if not MayBeBorg.__monostate:
MayBeBorg.__monostate = self.__dict__
else:
self.__dict__ = MayBeBorg.__monostate
return
self.wings = ..
self.beak = ..