2009-08-23 21 views
61

¿Por qué el Borg pattern es mejor que el Singleton pattern?¿Por qué el patrón de Borg es mejor que el patrón de Singleton en Python?

Lo pido porque no los veo dando como resultado algo 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() 

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() 

Lo que quiero mostrar aquí es que el objeto de servicio, ya sea implementada como Borg o Singleton, tiene un estado interno no trivial (que proporciona una cierta servicio basado en él) (me refiero a que tiene que ser algo útil, no es un Singleton/Borg solo por diversión).

Y este estado tiene que ser inited. Aquí la implementación de Singleton es más sencilla, ya que tratamos init como la configuración del estado global. Me resulta incómodo que el objeto Borg tenga que consultar su estado interno para ver si debería actualizarse.

Se vuelve peor cuanto más interno se encuentre. Por ejemplo, si el objeto tiene que escuchar la señal de corte 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.

+1

Borg pattern?^_^Había oído hablar de él por primera vez como http://c2.com/cgi/wiki?MonostatePattern –

+8

Monostate? Somos los Martellis. Decimos Borg. – u0b34a0f6ae

Respuesta

46

La verdadera razón por la que borg es diferente se reduce a las subclases.

Si subclase A Borg, la subclase objetos tienen el mismo estado que sus padres clases de objetos, 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.

También en el patrón singleton los objetos son en realidad la misma, no sólo el estado (a pesar de que el Estado es el único que realmente importa).

+1

> También en el patrón singleton los objetos son en realidad los mismos, no solo el estado (aunque el estado es lo único que realmente importa). ¿Por qué es eso algo malo? – agiliq

+0

buena pregunta uswaretech, es una parte de mi pregunta anterior. ¿Qué es eso dicho como malo? – u0b34a0f6ae

+2

No dije que fuera algo malo. Fue una observación sin opinión sobre las diferencias. Perdón por la confusion. A veces, el singleton será mejor de hecho, si, por ejemplo, haces algún control sobre los objetos id por id (obj), aunque esto es raro. –

13

No lo es. Lo que generalmente no se recomienda es un patrón de esta manera 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 

en el que utiliza un método de clase para obtener la instancia en lugar del constructor. La metaprogramación de Python permite métodos mucho mejores, p. 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() 
+0

+1 El patrón Monostate (Borg) es _worse_ que Singleton (sí, es posible) porque private a = new Borg(); private b = new Borg(); b.mutate(); y a es cambiado! ¿Qué tan confuso es eso? –

+4

¿Mejor/peor? Eso dependería de tu uso, ¿no es así? Puedo pensar en varios casos en los que desearía que se conservara un estado así. – RickyA

+4

Esto no es un problema, @MichaelDeardeuff. Esto es _comportamiento intencionado_. Deberían ser iguales. Un problema en mi humilde opinión en el patrón borg es que si agrega algunas variables de inicialización en el método Borg .__ init__, como 'self.text =" "', entonces cambie ese objeto como 'borg1.text =" blah "' y luego cree una instancia un objeto nuevo 'borg2 = Borg()" - wham! todos los atributos de borg1 que se inicializan en __init__ están sombreados, por lo que crear instancias es imposible - o mejor: ¡En el patrón de Borg, NO PUEDE inicializar los atributos de miembro en el método __init__! – nerdoc

7

Una clase básicamente describe cómo se puede acceder (lectura/escritura) el estado interno de su objeto.

En el patrón singleton que sólo puede tener una sola clase, es decir, todos los objetos que van a dar los mismos puntos de acceso al estado compartido. Esto significa que si tiene que proporcionar una API extendida, necesitará escribir un contenedor, envolviendo alrededor del singleton

En el patrón borg, puede ampliar la clase base "borg" y, por lo tanto, extenderla más cómodamente la API para tu gusto.

7

Es sólo que mejor en aquellos pocos casos en los que tiene actualmente 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.

17

En python, si desea un "objeto" único al que pueda acceder desde cualquier lugar, solo cree una clase Unique que solo contenga atributos estáticos, @staticmethod sy @classmethod s; podrías llamarlo Patrón Único. Aquí implemento y comparar los patrones: 3

únicos

#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 

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:

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 

En mi opinión, la aplicación única es la más fácil, a continuación, Borg y finalmente Singleton con un número feo de dos funciones necesarias para su definición.

0

Además, el patrón tipo 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 = .. 
Cuestiones relacionadas