Dlaczego wzór Borga jest lepszy niż wzór Singletona ?
Pytam, ponieważ nie widzę, aby skutkowały czymś innym.
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()
Singel:
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()
Chcę tutaj pokazać, że obiekt usługi, niezależnie od tego, czy jest zaimplementowany jako Borg czy Singleton, ma nietrywialny stan wewnętrzny (zapewnia pewną usługę na jego podstawie) (mam na myśli to, że musi to być coś użytecznego, a nie Singleton / Borg tylko dla zabawa).
I ten stan musi zostać zainicjowany. W tym przypadku implementacja Singletona jest prostsza, ponieważ traktujemy init jako konfigurację stanu globalnego. Uważam za niezręczne, że obiekt Borg musi sprawdzać swój stan wewnętrzny, aby sprawdzić, czy powinien się zaktualizować.
Staje się gorzej, im bardziej masz stan wewnętrzny. Na przykład, jeśli obiekt musi nasłuchiwać sygnału rozłączania Aplikacji, aby zapisać swój rejestr na dysku, ta rejestracja również powinna być wykonana tylko raz, a jest to łatwiejsze w przypadku Singletona.
Odpowiedzi:
Prawdziwy powód, dla którego borg jest inny, sprowadza się do podklasy.
Jeśli utworzysz podklasę borg, obiekty podklasy mają ten sam stan, co obiekty ich klas nadrzędnych, chyba że jawnie nadpiszesz stan współużytkowania w tej podklasie. Każda podklasa wzorca singleton ma swój własny stan i dlatego będzie wytwarzać różne obiekty.
Również we wzorcu singletonowym obiekty są w rzeczywistości takie same, a nie tylko stan (chociaż stan jest jedyną rzeczą, która naprawdę ma znaczenie).
źródło
None
w Pythonie jest Singleton, a nie przykład wzorca Borg?x is None
kontrole. Ponadto None jest przypadkiem specjalnym, ponieważ nie możemy tworzyć podklas None.W Pythonie, jeśli chcesz mieć unikalny „obiekt”, do którego masz dostęp z dowolnego miejsca, po prostu utwórz klasę,
Unique
która zawiera tylko statyczne atrybuty,@staticmethod
s i@classmethod
s; można to nazwać Unikalnym Wzorem. Tutaj implementuję i porównuję 3 wzorce:Wyjątkowy
#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
Singel
#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))
Wynik:
Moim zdaniem implementacja Unique jest najłatwiejsza, potem Borg i wreszcie Singleton z brzydką liczbą dwóch funkcji potrzebnych do jej zdefiniowania.
źródło
Nie jest. To, co generalnie nie jest zalecane, to taki wzorzec w Pythonie:
class Singleton(object): _instance = None def __init__(self, ...): ... @classmethod def instance(cls): if cls._instance is None: cls._instance = cls(...) return cls._instance
gdzie używasz metody klasy, aby uzyskać instancję zamiast konstruktora. Metaprogramowanie w Pythonie pozwala na znacznie lepsze metody, np. Tę z Wikipedii :
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()
źródło
self.text = ""
, to zmień ten obiekt na przykład,borg1.text = "blah"
a następnie utwórz instancję nowego obiektu `borg2 = Borg ()" - bum! Wszystkie atrybuty borg1, które są inicjowane w init są biczowane. więc tworzenie instancji jest niemożliwe - lub lepiej: we wzorcu Borg NIEif
sprawdzenie, czy istnieje już instancja, a jeśli tak, jest ona zwracana BEZ nadpisującej inicjalizacji!if __monostate: return
a potem wykonaj self.foo = 'bar'Klasa w zasadzie opisuje, w jaki sposób można uzyskać dostęp (odczyt / zapis) do stanu wewnętrznego obiektu.
We wzorcu singleton możesz mieć tylko jedną klasę, tzn. Wszystkie Twoje obiekty dadzą ci te same punkty dostępu do wspólnego stanu. Oznacza to, że jeśli musisz zapewnić rozszerzone API, będziesz musiał napisać wrapper, zawijający się wokół singletona
We wzorcu borg możesz rozszerzyć podstawową klasę „borg”, a tym samym wygodniej rozszerzyć API według własnego uznania.
źródło
Jest lepiej tylko w tych kilku przypadkach, w których faktycznie masz różnicę. Tak jak w przypadku podklasy. Wzorzec Borg jest niezwykle niezwykły, nigdy nie potrzebowałem go naprawdę przez dziesięć lat programowania w Pythonie.
źródło
Ponadto wzorzec podobny do Borga pozwala użytkownikom klasy na wybór, czy chcą współdzielić stan, czy utworzyć oddzielną instancję. (czy to może 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 = ..
źródło