PythonのBorgパターンがSingletonパターンよりも優れているのはなぜですか


82

ボーグパターンシングルトンパターンよりも優れているのはなぜですか?

私はそれらが何か違う結果をもたらすのを見ないので尋ねます。

ボーグ:

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だけではなく便利なものでなければなりません楽しい)。

そして、この状態を初期化する必要があります。ここでは、initをグローバル状態のセットアップとして扱うため、シングルトンの実装はより簡単です。Borgオブジェクトがそれ自体を更新する必要があるかどうかを確認するために、その内部状態を照会する必要があるのは厄介だと思います。

内部状態が多いほど悪化します。たとえば、オブジェクトがそのレジスタをディスクに保存するためにアプリケーションのティアダウン信号をリッスンする必要がある場合、その登録も1回だけ実行する必要があり、これはシングルトンを使用すると簡単になります。


1
ボーグパターン?^ _ ^私はそれをc2.com/cgi/wiki?MonostatePattern
Jeffrey Hantin 2010年

9
モノステート?私たちはマルテリスです。ボーグと言います。
u0b34a0f6ae 2010年

回答:


66

ボルグが異なる本当の理由は、サブクラス化にあります。

ボーグをサブクラス化する場合、そのサブクラスの共有状態を明示的にオーバーライドしない限り、サブクラスのオブジェクトは親クラスのオブジェクトと同じ状態になります。シングルトンパターンの各サブクラスには独自の状態があるため、異なるオブジェクトが生成されます。

また、シングルトンパターンでは、オブジェクトは実際には同じであり、状態だけではありません(実際に重要なのは状態だけですが)。


1
>また、シングルトンパターンでは、オブジェクトは実際には状態だけでなく同じです(状態だけが本当に重要ですが)。なぜそれが悪いのですか?
agiliq 2009

良い質問uswaretech、それは上記の私の質問の一部です。それは悪いとは何ですか?
u0b34a0f6ae 2009

2
悪いことだとは言いませんでした。それは違いについての意見のない観察でした。混乱させて申し訳ありません。たとえば、id(obj)によってオブジェクトidをチェックする場合、これはまれですが、シングルトンの方が実際に優れている場合があります。
David Raznick

Noneでは、Pythonではどのようにシングルトンであり、ボーグパターンの例ではありませんか?
Chang Zhao

@ChangZhao:Noneの場合、状態を共有するだけでなく、同じIDを持つ必要があるためです。x is Noneチェックを行います。さらに、Noneのサブクラスを作成できないため、Noneは特殊なケースです。
オリーブコーダー

23

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

出力:

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

私の意見では、Unique実装が最も簡単で、次にBorg、最後にSingletonであり、その定義に必要な2つの関数の醜い数があります。


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のメタプログラミングは、はるかに優れたメソッドを可能にします。たとえば、ウィキペディアのメソッドです。

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モノステート(Borg)パターンはシングルトンよりも悪いです(はい、可能です)。なぜならprivate a = new Borg(); プライベートb = new Borg(); b.mutate(); そしてaが変更されました!それはどれほど混乱していますか?
Michael Deardeuff 2011年

5
最高/悪い?それはあなたのユースケースに依存しますね。そのように状態を保存したい場合がたくさん考えられます。
RickyA 2012年

5
これは問題ではありません、@ MichaelDeardeuff。これは意図された動作です。それらは同じである必要があります。ボーグパターンの問題IMHOは、のようにBorg .__ init__メソッドに初期化変数を追加した場合self.text = ""、そのオブジェクトを次のように変更してからborg1.text = "blah"、新しいオブジェクト `borg2 = Borg()"をインスタンス化することです。initで初期化されるので、インスタンス化は不可能です-またはそれ以上:Borgパターンでは、initメソッドでメンバー属性を初期化しないでください!
nerdoc 2013年

これはシングルトンで可能です。これはif、インスタンスがすでに存在するかどうかのチェックがあり、存在する場合は、オーバーライドする初期化なしで返されるだけだからです。
nerdoc 2013年

Borg initでも同じことができます(そしてそうすべきです)。if __monostate: returnその後、self.foo = 'bar'を実行します
volodymyr 2017年

8

クラスは基本的に、オブジェクトの内部状態にアクセス(読み取り/書き込み)する方法を記述します。

シングルトンパターンでは、単一のクラスしか持つことができません。つまり、すべてのオブジェクトが共有状態への同じアクセスポイントを提供します。つまり、拡張APIを提供する必要がある場合は、シングルトンをラップするラッパーを作成する必要があります。

ボーグパターンでは、基本の「ボーグ」クラスを拡張できるため、好みに合わせてAPIをより便利に拡張できます。


8

それはあなたが実際に違いを持っ​​ているそれらのいくつかの場合にのみ良いです。サブクラス化するときのように。ボーグのパターンは非常に珍しいものです。10年間の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 = ..
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.