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またはシングルトンとして実装されているかどうかにかかわらず、重要な内部状態を持っていることです(それに基づいて何らかのサービスを提供します)(つまり、シングルトン/ボーグではなく、楽しい)。
そして、この状態を初期化する必要があります。ここでは、initをグローバル状態のセットアップとして扱うため、シングルトンの実装はより簡単です。 Borgオブジェクトが内部状態を照会して、それ自体を更新する必要があるかどうかを確認する必要があるのは不自然です。
あなたが持っている内部状態が悪化するほど悪化します。たとえば、オブジェクトがアプリケーションのティアダウンシグナルをリッスンしてディスクにレジスタを保存する必要がある場合、その登録も1回だけ行う必要があります。これはシングルトンの方が簡単です。
ボーグが異なる本当の理由は、サブクラス化にあります。
ボルグをサブクラス化すると、サブクラスのオブジェクトは、そのサブクラスの共有状態を明示的にオーバーライドしない限り、親クラスオブジェクトと同じ状態になります。シングルトンパターンの各サブクラスには独自の状態があるため、異なるオブジェクトが生成されます。
また、シングルトンパターンでは、オブジェクトは状態だけでなく実際には同じです(実際に重要なのは状態だけですが)。
In python静的属性のみを含むクラスUnique
を作成するだけで、どこからでもアクセスできる一意の「オブジェクト」が必要な場合は、@staticmethod
砂 @classmethod
s;ユニークパターンと呼ぶことができます。ここで、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、そして最後にシングルトンはその定義に必要な2つの関数のい数を持っています。
そうではない。一般的に推奨されないのは、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のメタプログラミングにより、はるかに優れたメソッドが可能になります。 ウィキペディア :
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つのクラスしか持つことができません。つまり、すべてのオブジェクトが共有状態への同じアクセスポイントを提供します。これは、拡張APIを提供する必要がある場合は、シングルトンをラップするラッパーを作成する必要があることを意味します
Borgパターンでは、ベースの「borg」クラスを拡張することができ、それにより好みに合わせてAPIをより便利に拡張できます。
実際に違いがある少数の場合にのみ優れています。サブクラス化するときのように。 Borgパターンは非常に珍しいもので、10年の間に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 = ..