web-dev-qa-db-ja.com

PythonでBorgパターンがSingletonパターンよりも優れている理由

Borg patternSingleton 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回だけ行う必要があります。これはシングルトンの方が簡単です。

74
u0b34a0f6ae

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

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

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

57
David Raznick

In python静的属性のみを含むクラスUniqueを作成するだけで、どこからでもアクセスできる一意の「オブジェクト」が必要な場合は、@staticmethod@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、そして最後にシングルトンはその定義に必要な2つの関数のい数を持っています。

21
Cristian Garcia

そうではない。一般的に推奨されないのは、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()
13
bayer

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

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

Borgパターンでは、ベースの「borg」クラスを拡張することができ、それにより好みに合わせてAPIをより便利に拡張できます。

8
Zed

実際に違いがある少数の場合にのみ優れています。サブクラス化するときのように。 Borgパターンは非常に珍しいもので、10年の間にPythonプログラミングで実際に必要になることはありませんでした。

8
Lennart Regebro

また、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 = ..
1
volodymyr