为什么博格模式比 Python 中的单例模式模式更好

为什么 博格人模式单例模式好?

我这么问是因为我不认为他们会有什么不同。

博格:

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视为全局状态的设置。我觉得这很尴尬,博格对象必须查询其内部状态,看看是否应该更新自己。

你的内在状态越严重,情况就越糟。例如,如果对象必须听应用程序的拆卸信号才能将它的寄存器保存到磁盘,那么注册也只应该执行一次,而使用 Singleton 会更容易。

34904 次浏览

It is not. What is generally not recommended is a pattern like this 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

where you use a class method to get the instance instead of the constructor. Python's metaprogramming allows much better methods, e.g. the one on 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()

A class basically describes how you can access (read/write) the internal state of your object.

In the singleton pattern you can only have a single class, i.e. all your objects will give you the same access points to the shared state. This means that if you have to provide an extended API, you will need to write a wrapper, wrapping around the singleton

In the borg pattern you are able to extend the base "borg" class, and thereby more conveniently extend the API for your taste.

The real reason that borg is different comes down to subclassing.

If you subclass a borg, the subclass' objects have the same state as their parents classes objects, unless you explicitly override the shared state in that subclass. Each subclass of the singleton pattern has its own state and therefore will produce different objects.

Also in the singleton pattern the objects are actually the same, not just the state (even though the state is the only thing that really matters).

It's only better in those few cases where you actually have a difference. Like when you subclass. The Borg pattern is extremely unusual, I've never needed it for real in ten years of Python programming.

In python if you want a unique "object" that you can access from anywhere just create a class Unique that only contains static attributes, @staticmethods, and @classmethods; you could call it the Unique Pattern. Here I implement and compare the 3 patterns:

Unique

#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

Test

#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))

Output:

SINGLETON

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

In my opinion, Unique implementation is the easiest, then Borg and finally Singleton with an ugly number of two functions needed for its definition.

Also, Borg-like pattern allows users of the class to choice if they want to share the state or create a separate instance. (whether or not this may be a good idea is a separate topic)

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