python中为什么borg模式比singleton模式更好?

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中,如果您想要一个可以从任何地方访问的唯一"对象",只需创建一个只包含静态属性的类Unique@staticmethods和@classmethods;您可以称之为唯一模式。在这里,我实现并比较三种模式:

独特的

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