Singletonパターン (5) - Borgの方法


Singletonにはサブクラス化したとき、

  1. 各サブクラス毎にインスタンスは唯1つ
  2. クラスのツリー全体でインスタンスは唯1つ

のどちらにするのか、という問題が生じます。

Pythonでは、Borgの方法というものを使えば、このどちらにするのかを、自由に選択できます。

なお、Borgの方法は『Rubyによるデザインパターン』ではなく『Pythonクックブック』から、拝借しました。

class Borg(object):
    _shared_state = {}
    def __new__(cls, *a, **kw):
        instance = object.__new__(cls, *a, **kw)
        instance.__dict__ = cls._shared_state
        return instance
    
    def set_name(self, name):
        self.name = name
    
    def get_name(self):
        return self.name

class Example(Borg):
    #基底クラスと状態を共有する
    pass

class Example2(Borg):
    #基底クラスと状態を共有しない
    _shared_state = {}

if __name__ == "__main__":
    
    s1 = Borg()
    s2 = Example()
    s3 = Example2()
    s4 = Example2()
    s1.set_name("egg")
    s2.set_name("spam")
    s3.set_name("hoge")
    s4.set_name("piyo")

    print s1, s1.get_name()
    print s2, s2.get_name()
    print s3, s3.get_name()
    print s4, s4.get_name()

Pythonの「クラスの属性=辞書」という特性を利用します。

__new__で、インスタンスの属性辞書を、ある特定の辞書に変更します。

BorgではSingletonと違って、インスタンスの唯一性は保たれません。

a = Borg()
b = Borg()
print a is b # => None

しかし必要なのは、インスタンスそのものの同一性ではなく、振る舞いの同一性なので、Borgの方法はSingletonの代替になりうるのです。