概要
Borgパターン(Borgの読みは、ボルグもしくはボーグ)は、古典的なSingletonパターンを改良したもの。Singletonパターンでは、Singletonを表現するすべてのオブジェクトが、同じインスタンスを共有する必要がある。Borgパターンでは、すべての表現が同じ状態(インスタンスのすべての属性が同じディクショナリを指す)を共有することを保証しながら、すべての表現がユニークなインスタンスを持つことができる。
全ての表現が同じインスタンスを指すのであれば、関数や変数を持つクラスレスのモジュールを使用すれば良いと考えることができる。(つまり、Singletonはアンチパターンと言える。)Borgパターンは、意味のある継承とオブジェクトのインスタンスの保存を可能にすると同時に状態の共有を可能にしている。
具体的な違い
Borgをサブクラス化した場合、そのオブジェクトは、共有状態を明示的にオーバーライドしない限り、親クラスのオブジェクトと同じ状態になる。Singletonパターンの各サブクラスは独自の状態を持つため、異なるオブジェクトを生成する。また、Singletonパターンでは、(状態のみが重要なものであっても)オブジェクトが同じであり、インスタンスの状態だけではない。
実装例
class Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
class SubBorg(Borg):
def __init__(self, **kwargs):
Borg.__init__(self)
for key, value in kwargs.items():
setattr(self, key, value)
if __name__ == '__main__':
s_instance_1 = SubBorg(v=-1, v1="hoge")
s_instance_2 = SubBorg(v=42, v2="hello")
print(s_instance_1._shared_state is s_instance_2._shared_state) # True
print("v: {}".format(s_instance_1.v == s_instance_2.v == 42)) # True
print("v1: {}".format(s_instance_1.v1 == s_instance_2.v1 == "hoge")) # True
print("v2: {}".format(s_instance_1.v2 == s_instance_2.v2 == "hello")) # True