为什么Borg模式比Python中的Singleton模式更好


80

为什么Borg模式Singleton模式更好?

我问是因为我看不到它们会导致任何不同。

博格:

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对象必须查询其内部状态以查看是否应该自我更新很尴尬。

内部状态越多,情况就越糟。例如,如果对象必须侦听应用程序的拆除信号以将其寄存器保存到磁盘,则该注册也应该只执行一次,而使用Singleton则更容易。


1
博格模式?^ _ ^我第一次听说它是c2.com/cgi/wiki?MonostatePattern
Jeffrey Hantin

9
单态?我们是马爹利人。我们说博格。
u0b34a0f6ae 2010年

Answers:


64

博格与众不同的真正原因归结为子类化。

如果将borg子类化,则子类的对象与其父类对象具有相同的状态,除非您显式覆盖该子类中的共享状态。单例模式的每个子类都有其自己的状态,因此将产生不同的对象。

同样在单例模式中,对象实际上是相同的,而不仅仅是状态(即使状态是唯一真正重要的东西)。


1
>同样在单例模式中,对象实际上是相同的,而不仅仅是状态(即使状态是唯一真正重要的东西)。为什么这是一件坏事?
09年

很好的问题uswaretech,这是我上面的问题的一部分。那说什么不好?
u0b34a0f6ae

2
我没有说这是一件坏事。这是对差异的无意见的观察。对困惑感到抱歉。有时单例实际上会更好,例如,即使您很少通过id(obj)对对象id进行检查,即使这种情况很少见。
David Raznick 09年

那么None在python中是Singleton而不是Borg模式的例子吗?
Chang Zhao

@ChangZhao:因为在None的情况下,我们需要具有相同的身份,而不仅仅是共享状态。我们进行x is None检查。此外,无是一种特殊情况,因为我们无法创建无的子类。
Olivecoder

22

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

输出:

辛格尔顿

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,其定义所需的两个函数数量很少。


14

它不是。通常不建议在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()

+1 Monostate(Borg)模式比Singleton(是的,有可能),因为private a = new Borg(); 私人b =新的Borg(); b.mutate(); 并且改变了!那有多令人困惑?
Michael Deardeuff

5
最好/更坏?那将取决于您的用例,不是吗。我可以想到很多情况下您想要保留状态的情况。
RickyA 2012年

5
@MichaelDeardeuff,这不是问题。这是预期的行为。它们应该是相同的。borg模式中的恕我直言的一个问题是,如果您在Borg .__ init__方法中添加了一些初始化变量,例如self.text = "",则更改该对象borg1.text = "blah",然后实例化一个新的对象“ borg2 = Borg()”-哇!初始化init会被鞭打。因此无法进行实例化-或更好:在Borg模式中,您
不得

在Singleton中,这是可能的,因为可以if检查是否已经有一个实例,如果是,则返回该实例而无需进行覆盖初始化!
nerdoc

在Borg init中可以(并且应该)进行同样的操作。if __monostate: return,之后做你self.foo =“吧”
沃洛

8

一个类基本上描述了如何访问(读/写)对象的内部状态。

在单例模式中,您只能有一个类,即所有对象将为您提供相同的访问共享状态的访问点。这意味着,如果必须提供扩展的API,则需要编写包装器,将单例包装

在borg模式中,您可以扩展基本的“ borg”类,从而更方便地扩展您的API。


8

只有在您实际上有所不同的少数情况下,这才更好。就像您继承子类时一样。Borg模式是非常不寻常的,在十年的Python编程中,我从未真正需要它。


2

同样,类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 = ..
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.