¿Por qué el patrón Borg es mejor que el patrón Singleton ?
Pregunto porque no veo que resulten en nada diferente.
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()
Único:
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()
Lo que quiero mostrar aquí es que el objeto de servicio, ya sea implementado como Borg o Singleton, tiene un estado interno no trivial (proporciona algún servicio basado en él) (quiero decir que tiene que ser algo útil, no es un Singleton / Borg solo para divertido).
Y este estado debe iniciarse. Aquí, la implementación de Singleton es más sencilla, ya que tratamos a init como la configuración del estado global. Me resulta extraño que el objeto Borg tenga que consultar su estado interno para ver si debería actualizarse.
Se vuelve peor cuanto más estado interno tienes. Por ejemplo, si el objeto tiene que escuchar la señal de eliminación de la aplicación para guardar su registro en el disco, ese registro solo debe hacerse una vez también, y esto es más fácil con un Singleton.
Respuestas:
La verdadera razón por la que Borg es diferente se reduce a las subclases.
Si subclasifica un borg, los objetos de la subclase tienen el mismo estado que los objetos de las clases principales, a menos que anule explícitamente el estado compartido en esa subclase. Cada subclase del patrón singleton tiene su propio estado y, por lo tanto, producirá diferentes objetos.
Además, en el patrón singleton los objetos son en realidad iguales, no solo el estado (aunque el estado es lo único que realmente importa).
fuente
None
en Python es un Singleton y no un ejemplo de patrón Borg?x is None
comprobaciones. Además, None es un caso especial ya que no podemos crear subclases de None.En Python, si desea un "objeto" único al que pueda acceder desde cualquier lugar, simplemente cree una clase
Unique
que solo contenga atributos estáticos,@staticmethod
sy@classmethod
s; podrías llamarlo el Patrón Único. Aquí implemento y comparo los 3 patrones:Único
#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
único
#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
Prueba
#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))
Salida:
En mi opinión, la implementación de Unique es la más fácil, luego Borg y finalmente Singleton con una fea cantidad de dos funciones necesarias para su definición.
fuente
No lo es. Lo que generalmente no se recomienda es un patrón como este 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
donde usa un método de clase para obtener la instancia en lugar del constructor. La metaprogramación de Python permite métodos mucho mejores, por ejemplo, el de 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()
fuente
self.text = ""
, luego cambie ese objeto comoborg1.text = "blah"
y luego cree una instancia de un nuevo objeto `borg2 = Borg ()" - ¡zas! Todos los atributos borg1 que se inicializan en init . whiped están tan instanciar es imposible - o mejor: miembros en el patrón de Borg, no podrá inicializar los atributos en el init método!if
verificación de si ya existe una instancia, y si es así, ¡simplemente se devuelve SIN una inicialización primordial!if __monostate: return
y después de eso haz tu self.foo = 'bar'Una clase básicamente describe cómo puede acceder (leer / escribir) el estado interno de su objeto.
En el patrón singleton solo puede tener una única clase, es decir, todos sus objetos le darán los mismos puntos de acceso al estado compartido. Esto significa que si tiene que proporcionar una API extendida, deberá escribir un contenedor, envolviendo el singleton
En el patrón borg puede extender la clase base "borg" y, por lo tanto, extender más convenientemente la API para su gusto.
fuente
Solo es mejor en esos pocos casos en los que realmente hay una diferencia. Como cuando subclases. El patrón Borg es extremadamente inusual, nunca lo he necesitado de verdad en diez años de programación en Python.
fuente
Además, el patrón similar a Borg permite a los usuarios de la clase elegir si desean compartir el estado o crear una instancia separada. (si esto puede ser una buena idea o no es un tema aparte)
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 = ..
fuente