Why is the Borg pattern better than the Singleton pattern in Python
为什么伯格模式比单体模式好?
我问是因为我看不出它们会导致什么不同。
Borg:
1 2 3 4 5 6 7 8 | 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:
1 2 3 4 5 6 7 8 | 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实现,都有一个非常重要的内部状态(它提供了一些基于它的服务)(我的意思是它必须是有用的,而不是仅仅为了好玩而单独使用/borg)。
这个状态必须被初始化。在这里,单例实现更简单,因为我们将init视为全局状态的设置。我觉得奇怪的是,borg对象必须查询它的内部状态,看看它是否应该更新自己。
你的内部状态越差。例如,如果对象必须监听应用程序的拆卸信号以将其寄存器保存到磁盘上,那么该注册也只应进行一次,而使用单例注册更容易。
BORG不同的真正原因归结为子类化。
如果子类是BORG,则子类对象的状态与其父类对象的状态相同,除非显式重写该子类中的共享状态。单例模式的每个子类都有自己的状态,因此将产生不同的对象。
在单例模式中,对象实际上是相同的,而不仅仅是状态(即使状态是唯一真正重要的东西)。
在python中,如果您想要一个可以从任何地方访问的唯一"对象",只需创建一个只包含静态属性的类
独特的
1 2 3 4 5 6 7 8 | #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 |
独生子女
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #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 |
博格
1 2 3 4 5 6 7 8 9 10 11 12 13 | #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 |
试验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #SINGLETON print" SINGLETON " 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 = {} ".format(B.x,A.x) print "Are A and B the same object? Answer: {}".format(id(A)==id(B)) #BORG print" BORG " 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 = {} ".format(B.x,A.x) print "Are A and B the same object? Answer: {}".format(id(A)==id(B)) #UNIQUE print" UNIQUE " 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 = {} ".format(B.x,A.x) print "Are A and B the same object? Answer: {}".format(id(A)==id(B)) |
输出:
SINGLETON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 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
在我看来,惟一的实现是最简单的,然后是borg,最后是singleton,其定义需要两个丑陋的函数。
不是这样。通常不建议在python中使用这样的模式:
1 2 3 4 5 6 7 8 9 10 11 12 | 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上的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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() |
只有在你真正有不同的情况下才会更好。就像你的子类。Borg模式是非常不寻常的,我在十年的Python编程中从未真正需要它。
类基本上描述了如何访问(读/写)对象的内部状态。
在单例模式中,您只能有一个类,即所有对象都将为您提供对共享状态的相同访问点。这意味着,如果必须提供扩展的API,则需要编写一个包装器,包装单例
在borg模式中,您可以扩展基本的"borg"类,从而更方便地扩展API以满足您的口味。
此外,类的borg-like模式允许类的用户选择是否要共享状态或创建单独的实例。(这是否是一个好主意是一个单独的主题)
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 = .. |