2009-08-23 12 views
61

Dlaczego Borg pattern jest lepszy niż Singleton pattern?Dlaczego wzór Borg jest lepszy niż wzór Singleton w Pythonie

Pytam, ponieważ ich nie widzę, co prowadzi do czegoś innego.

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

Co chcę, aby wyświetlić o to, że przedmiot usługi, czy zaimplementowane jako Borg lub Singleton, posiada nietrywialne stany wewnętrzne (to zapewnia jedne usługa oparta na tym) (mam na myśli, że musi to być coś pożytecznego, to nie jest Singleton/Borg tylko dla zabawy).

I ten stan musi zostać zainicjowany. Tutaj implementacja Singletona jest prostsza, ponieważ traktujemy init jako konfigurację stanu globalnego. Uważam to za niezręczne, że obiekt Borg musi sprawdzać swój stan wewnętrzny, aby sprawdzić, czy powinien sam się zaktualizować.

Coraz gorzej, im bardziej masz wewnętrzny stan. Na przykład, jeśli obiekt musi słuchać sygnału utraty aplikacji, aby zapisać swój rejestr na dysku, rejestracja ta powinna być wykonana tylko raz, a to jest łatwiejsze z Singletonem.

+1

Wzór Borg?^_^Najpierw usłyszałem o tym jako http://c2.com/cgi/wiki?MonostatePattern –

+8

Monostate? Jesteśmy Martellis. Mówimy Borg. – u0b34a0f6ae

Odpowiedz

46

Prawdziwy powód, dla którego borg jest inny, sprowadza się do podklasy.

Jeśli podklasy borg, obiekty podklasy mają taki sam stan, jak ich rodziców obiektów klasy, chyba że jawnie zastąpić wspólny stan w tej podklasy. Każda podklasa wzorca singleton ma swój własny stan i dlatego będzie wytwarzać różne obiekty.

Również w układzie singleton obiekty są w rzeczywistości takie same, nie tylko stan (nawet jeśli stan jest jedyną rzeczą, która naprawdę ma znaczenie).

+1

> Również w układzie singleton obiekty są w rzeczywistości takie same, a nie tylko stan (nawet jeśli stan jest jedyną rzeczą, która naprawdę ma znaczenie) Dlaczego to jest złe? – agiliq

+0

dobre pytanie uswaretech, jest to część mojego pytania powyżej. Co jest powiedziane jako złe? – u0b34a0f6ae

+2

Nie powiedziałem, że to była zła rzecz. Była to bezstronna obserwacja różnic. Przepraszam za zamieszanie. Czasami singleton będzie lepszy, jeśli na przykład wykonasz jakąkolwiek kontrolę id obiektów przez id (obj), nawet jeśli jest to rzadkie. –

13

Nie jest. Generalnie nie zaleca się takiego wzorca w pytonie:

class Singleton(object): 

_instance = None 

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

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

w przypadku użycia metody klasy do pobrania instancji zamiast konstruktora. Metaprogramowanie w Pythonie pozwala na znacznie lepsze metody, np. jeden na 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 Wzór Monostatu (Borg) jest _worse_ niż Singleton (tak, jest to możliwe) ponieważ private a = new Borg(); private b = new Borg(); b.mutate(); a a się zmieniło! Jakie to mylące? –

+4

Najlepszy/gorszy? To by zależało od twojego przypadku użycia. Mogę wymyślić wiele przypadków, w których chciałbyś zachować stan w ten sposób. – RickyA

+4

To nie jest problem, @MichaelDeardeuff. To jest _właściwe zachowanie_. Powinny być takie same. Problem z IMHO w schemacie borg polega na tym, że jeśli dodasz kilka zmiennych inicjalizujących w metodzie Borg .__ init__, np. 'Self.text =" "', zmień ten obiekt, np. 'Borg1.text =" bla ", a następnie stwórz instancję nowy obiekt 'borg2 = Borg()" - wham! wszystkie atrybuty borg1, które są inicjowane w __init__ są biczowane, więc tworzenie instancji jest niemożliwe - lub lepsze: W schemacie Borg, NIE MOŻNA inicjować atrybutów członków w metodzie __init__! – nerdoc

7

Klasa zasadzie opisuje w jaki sposób można uzyskać dostęp (odczyt/zapis) wewnętrzny stan swojego obiektu.

W schemacie singleton można mieć tylko jedną klasę, tj. Wszystkie obiekty dają te same punkty dostępu do stanu współdzielonego. Oznacza to, że jeśli musisz podać rozszerzony interfejs API, musisz napisać opaskę, owijając pojedynczy singleton

W schemacie borg możesz rozszerzyć podstawową klasę "borg", a tym samym wygodniej ją rozszerzyć API dla Twojego gustu.

7

Jest to lepsze rozwiązanie tylko w tych niewielu przypadkach, w których faktycznie występuje różnica. Podobnie jak w przypadku podklasy. Wzór Borg jest niezwykle niezwykły, nigdy nie potrzebowałem go od dziesięciu lat programowania w Pythonie.

17

W pythonie, jeśli chcesz uzyskać unikalny "obiekt", do którego masz dostęp z dowolnego miejsca, utwórz klasę Unique, która zawiera tylko atrybuty statyczne, @staticmethod s oraz @classmethod s; możesz nazwać to Unikalnym Wzorem. Tu wdrożenia i porównać 3 wzoru:

Unikalne

#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 

test

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

wyjściowa:

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 

Moim zdaniem Wyjątkowa realizacja jest najprostszym, a następnie Borg i wreszcie Singleton z brzydkiego liczbie dwóch funkcji potrzebnych do jego definicji.

0

Również wzór przypominający Borg pozwala użytkownikom klasy wybrać, czy chcą udostępnić stan, czy utworzyć oddzielne wystąpienie. (niezależnie od tego, czy może to być dobry pomysł, to osobny temat)

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