为什么 Borg pattern 比 Singleton pattern 好?
我问是因为我没有看到它们导致任何不同。
博格:
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()
单身人士:
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()
我想在这里展示的是服务对象,无论是作为 Borg 还是 Singleton 实现,都有一个重要的内部状态(它提供一些基于它的服务)(我的意思是它必须是有用的,它不是一个 Singleton/Borg 只是为了乐趣)。
并且这个状态必须被启动。这里的 Singleton 实现更直接,因为我们将 init 视为全局状态的设置。我发现 Borg 对象必须查询其内部状态以查看它是否应该更新自己,这很尴尬。
你拥有的内在状态越多,情况就越糟糕。例如,如果对象必须侦听应用程序的拆卸信号才能将其寄存器保存到磁盘,则该注册也应该只完成一次,这对于单例来说更容易。
博格不同的真正原因归结为子类化。
如果您将一个 borg 子类化,则子类的对象具有与其父类对象相同的状态,除非您显式覆盖该子类中的共享状态。单例模式的每个子类都有自己的状态,因此会产生不同的对象。
同样在单例模式中,对象实际上是相同的,而不仅仅是状态(即使状态是唯一真正重要的东西)。
在 python 中,如果您想要一个可以从任何地方访问的唯一“对象”,只需创建一个仅包含静态属性、@staticmethod
和 @classmethod
的类 Unique
;你可以称之为独特的模式。在这里,我实现并比较了 3 种模式:
独特的
#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 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 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
测试
#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))
输出:
SINGLETON 起初 Bx = 1 和 Ax = 1 在 Ax = 2 之后 现在 Bx = 2 和 Ax = 2 A 和 B 是同一个对象吗?答案:真正的 BORG 起初 Bx = 1 和 Ax = 1 在 Ax = 2 之后 现在 Bx = 2 和 Ax = 2 A 和 B 是同一个对象吗?答案:错误 UNIQUE 起初 Bx = 1 和 Ax = 1 在 Ax = 2 之后 现在 Bx = 2 和 Ax = 2 A 和 B 是同一个对象吗?答案:是的
在我看来,Unique 实现是最简单的,然后是 Borg,最后是 Singleton,其定义所需的两个函数数量很少。
它不是。通常不推荐的是python中这样的模式:
class Singleton(object):
_instance = None
def __init__(self, ...):
...
@classmethod
def instance(cls):
if cls._instance is None:
cls._instance = cls(...)
return cls._instance
您使用类方法来获取实例而不是构造函数。 Python 的元编程允许更好的方法,例如 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()
self.text = ""
,然后像 borg1.text = "blah"
一样更改该对象,然后实例化一个新对象 `borg2 = Borg()" -哇!在 init 中初始化的所有 borg1 属性都被鞭打了。所以实例化是不可能的 - 或者更好:在 Borg 模式中,你不能在 init 方法中初始化成员属性!
if
检查是否已经存在一个实例,如果是,它只是在没有覆盖初始化的情况下返回!
if __monostate: return
然后做你的 self.foo='bar'
一个类基本上描述了如何访问(读/写)对象的内部状态。
在单例模式中,您只能拥有一个类,即所有对象都将为您提供共享状态的相同访问点。这意味着如果您必须提供扩展 API,您将需要编写一个包装器,将单例包装起来
在 borg 模式中,您可以扩展基本的“borg”类,从而更方便地根据您的喜好扩展 API。
只有在您实际上有差异的少数情况下才会更好。就像你的子类一样。 Borg 模式非常不寻常,在十年的 Python 编程中,我从未真正需要它。
此外,类 Borg 模式允许类的用户选择是要共享状态还是创建单独的实例。 (这是否是一个好主意是一个单独的话题)
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 = ..
None
如何是单例而不是 Borg 模式的示例?x is None
检查。此外,None 是一种特殊情况,因为我们无法创建 None 的子类。