Warum ist das Borg-Muster besser als das Singleton-Muster ?
Ich frage, weil ich nicht sehe, dass sie zu etwas anderem führen.
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()
Was ich hier anzeigen möchte, ist, dass das Serviceobjekt, ob als Borg oder Singleton implementiert, einen nicht trivialen internen Status hat (es bietet einen darauf basierenden Service) (ich meine, es muss etwas Nützliches sein, es ist kein Singleton / Borg nur für Spaß).
Und dieser Zustand muss eingeleitet werden. Hier ist die Singleton-Implementierung einfacher, da wir init als Aufbau des globalen Zustands behandeln. Ich finde es umständlich, dass das Borg-Objekt seinen internen Status abfragen muss, um zu sehen, ob es sich selbst aktualisieren soll.
Es wird schlimmer, je mehr innerer Zustand Sie haben. Wenn das Objekt beispielsweise das Teardown-Signal der Anwendung abhören muss, um sein Register auf der Festplatte zu speichern, sollte diese Registrierung ebenfalls nur einmal durchgeführt werden. Dies ist mit einem Singleton einfacher.
Antworten:
Der wahre Grund, warum Borg anders ist, liegt in der Unterklasse.
Wenn Sie eine Borg unterordnen, haben die Objekte der Unterklasse denselben Status wie die Objekte der übergeordneten Klassen, es sei denn, Sie überschreiben explizit den gemeinsam genutzten Status in dieser Unterklasse. Jede Unterklasse des Singleton-Musters hat ihren eigenen Status und erzeugt daher unterschiedliche Objekte.
Auch im Singleton-Muster sind die Objekte tatsächlich gleich, nicht nur der Zustand (obwohl der Zustand das einzige ist, was wirklich wichtig ist).
quelle
None
in Python ein Singleton und kein Beispiel für ein Borg-Muster?x is None
Überprüfungen. Darüber hinaus ist None ein Sonderfall, da wir keine Unterklassen von None erstellen können.Wenn Sie in Python ein eindeutiges "Objekt" möchten, auf das Sie von überall aus zugreifen können, erstellen Sie einfach eine Klasse
Unique
, die nur statische Attribute,@staticmethod
s und@classmethod
s enthält. man könnte es das einzigartige Muster nennen. Hier implementiere und vergleiche ich die 3 Muster:Einzigartig
#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
Prüfung
#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))
Ausgabe:
Meiner Meinung nach ist die eindeutige Implementierung am einfachsten, dann Borg und schließlich Singleton mit einer hässlichen Anzahl von zwei Funktionen, die für die Definition benötigt werden.
quelle
Es ist nicht. Was im Allgemeinen nicht empfohlen wird, ist ein Muster wie dieses in Python:
class Singleton(object): _instance = None def __init__(self, ...): ... @classmethod def instance(cls): if cls._instance is None: cls._instance = cls(...) return cls._instance
Dabei verwenden Sie eine Klassenmethode, um die Instanz anstelle des Konstruktors abzurufen. Die Metaprogrammierung von Python ermöglicht viel bessere Methoden, z. B. die auf 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()
quelle
self.text = ""
, dann ändern Sie dieses Objekt wieborg1.text = "blah"
und instanziieren Sie dann ein neues Objekt `borg2 = Borg ()" - wham! Alle borg1-Attribute, die werden in init initialisiert werden ausgepeitscht, so dass eine Instanziierung unmöglich ist - oder besser: Im Borg-Muster dürfen Sie Mitgliedsattribute in der init- Methode NICHT initialisieren !if
überprüft wird, ob bereits eine Instanz vorhanden ist, und wenn ja, wird sie nur OHNE überschreibende Initialisierung zurückgegeben!if __monostate: return
und danach mach dein self.foo = 'bar'Eine Klasse beschreibt im Wesentlichen, wie Sie auf den internen Status Ihres Objekts zugreifen (lesen / schreiben) können.
Im Singleton-Muster können Sie nur eine einzige Klasse haben, dh alle Ihre Objekte geben Ihnen dieselben Zugriffspunkte auf den gemeinsam genutzten Status. Dies bedeutet, dass Sie, wenn Sie eine erweiterte API bereitstellen müssen, einen Wrapper schreiben müssen, der den Singleton umschließt
Im Borg-Muster können Sie die Basisklasse "Borg" erweitern und dadurch die API bequemer nach Ihrem Geschmack erweitern.
quelle
Es ist nur in den wenigen Fällen besser, in denen Sie tatsächlich einen Unterschied haben. Wie wenn Sie Unterklasse. Das Borg-Muster ist äußerst ungewöhnlich, ich habe es in zehn Jahren Python-Programmierung nie wirklich gebraucht.
quelle
Außerdem können Benutzer der Klasse anhand eines Borg-ähnlichen Musters auswählen, ob sie den Status freigeben oder eine separate Instanz erstellen möchten. (Ob dies eine gute Idee ist oder nicht, ist ein separates Thema)
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 = ..
quelle