2009-08-23 16 views
61

Perché lo Borg pattern è migliore dello Singleton pattern?Perché il pattern Borg è migliore del pattern Singleton in Python

Chiedo perché non li vedo risultando in qualcosa di diverso.

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

Quello che voglio per visualizzare qui è che l'oggetto del servizio, se implementato come Borg o Singleton, ha uno stato interno non banale (fornisce alcune servizio basato su di esso) (Voglio dire che deve essere qualcosa di utile non è un Singleton/Borg solo per divertimento).

E questo stato deve essere inserito. Qui l'implementazione di Singleton è più semplice, poiché trattiamo lo init come impostazione dello stato globale. Trovo scomodo che l'oggetto Borg debba interrogare il suo stato interno per vedere se dovrebbe aggiornarsi.

Diventa peggio lo stato interno che hai. Ad esempio, se l'oggetto deve ascoltare il segnale di teardown dell'applicazione per salvare il suo registro su disco, tale registrazione deve essere eseguita solo una volta, e questo è più semplice con un Singleton.

+1

Modello Borg?^_^L'ho sentito per la prima volta come http://c2.com/cgi/wiki?MonostatePattern –

+8

Monostate? Noi siamo i Martellis. Diciamo Borg. – u0b34a0f6ae

risposta

46

La vera ragione per cui borg è diverso deriva dalla sottoclasse.

Se si sottoclasse un borg, gli oggetti della sottoclasse hanno lo stesso stato degli oggetti delle classi genitori, a meno che non si sovrascriva esplicitamente lo stato condiviso in tale sottoclasse. Ogni sottoclasse del modello singleton ha il proprio stato e quindi produrrà oggetti diversi.

Anche nel modello singleton gli oggetti sono effettivamente gli stessi, non solo lo stato (anche se lo stato è l'unica cosa che conta davvero).

+1

> Anche nel modello singleton gli oggetti sono effettivamente gli stessi, non solo lo stato (anche se lo stato è l'unica cosa che conta davvero) Perché è una cosa brutta? – agiliq

+0

buona domanda uswaretech, è una parte della mia domanda di cui sopra. Cosa si dice così male? – u0b34a0f6ae

+2

Non ho detto che era una brutta cosa. Era un'osservazione senza opinione sulle differenze. Dispiace per la confusione. A volte il singleton sarà migliore in effetti, se per esempio si fanno dei controlli sull'id oggetto con id (obj), anche se questo è raro. –

13

Non lo è. Ciò che non è generalmente consigliata è di un modello come questo in pitone:

class Singleton(object): 

_instance = None 

def __init__(self, ...): 
    ... 

@classmethod 
def instance(cls): 
    if cls._instance is None: 
    cls._instance = cls(...) 
    return cls._instance 

in cui si utilizza un metodo di classe per ottenere l'istanza al posto del costruttore. La metaprogrammazione di Python consente metodi molto migliori, ad es. quello sul 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 Il pattern Monostate (Borg) è _worse_ rispetto a Singleton (sì, è possibile) perché private a = new Borg(); privato b = nuovo Borg(); b.mutate(); e a è cambiato! Quanto è confuso? –

+4

Il migliore/peggiore? Ciò dipenderebbe dal tuo caso d'uso, no? Posso pensare a un numero di casi in cui vorresti che lo stato fosse conservato in quel modo. – RickyA

+4

Questo non è un problema, @ MichaelDeardeuff. Questo è inteso nel comportamento. Dovrebbero essere uguali. Un problema IMHO nel modello borg è che, se si aggiungono alcune variabili di inizializzazione nel metodo Borg .__ init__, come 'self.text =" "', quindi modificare tale oggetto come 'borg1.text =" blah "' e quindi creare un'istanza un nuovo oggetto 'borg2 = Borg()" - wham! tutti gli attributi borg1 che sono inizializzati in __init__ sono frullati, quindi l'istanziazione è impossibile - o meglio: nel modello Borg, NON PUO 'inizializzare gli attributi del membro nel metodo __init__! – nerdoc

7

Una classe descrive fondamentalmente come è possibile accedere (lettura/scrittura) lo stato interno del vostro oggetto.

Nel modello singleton è possibile avere una sola classe, ovvero tutti gli oggetti forniranno gli stessi punti di accesso allo stato condiviso. Ciò significa che se devi fornire un'API estesa, dovrai scrivere un wrapper, avvolgendo il singleton

Nel modello borg puoi estendere la classe "borg" di base, e quindi estendere più convenientemente l'API per i tuoi gusti.

7

È meglio solo in quei pochi casi in cui effettivamente si fa la differenza. Come quando si sottoclasse. Il pattern di Borg è estremamente insolito, non ne ho mai avuto bisogno per davvero in dieci anni di programmazione Python.

17

In python se si desidera un "oggetto" univoco a cui è possibile accedere da qualsiasi luogo, basta creare una classe Unique che contenga solo attributi statici, @staticmethod s e @classmethod s; potresti chiamarlo il Pattern Unico. Qui a implementare e confronta i 3 modelli:

unici

#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 

prova

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

uscita:

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 

A mio parere, l'implementazione Unique è il più facile, poi Borg e, infine, Singleton, con un numero brutto di due funzioni necessarie per la sua definizione.

0

Inoltre, il modello di tipo Borg consente agli utenti della classe di scegliere se desiderano condividere lo stato o creare un'istanza separata. (se questa potrebbe essere una buona idea è un argomento separato)

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 = .. 
Problemi correlati