Borg 패턴이 Python의 Singleton 패턴보다 나은 이유


82

Borg 패턴Singleton 패턴 보다 나은 이유는 무엇 입니까?

나는 그들이 다른 결과를 낳지 않기 때문에 묻습니다.

보그 :

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 구현은 더 간단합니다. init 를 전역 상태의 설정으로 취급 하기 때문입니다. Borg 개체가 자체적으로 업데이트해야하는지 확인하기 위해 내부 상태를 쿼리해야하는 것이 어색합니다.

내부 상태가 많을수록 악화됩니다. 예를 들어, 객체가 레지스터를 디스크에 저장하기 위해 응용 프로그램의 분해 신호를 수신해야하는 경우 해당 등록도 한 번만 수행해야하며 Singleton을 사용하면 더 쉽습니다.



9
모노 스테이트? 우리는 Martellis입니다. 우리는 Borg라고 말합니다.
u0b34a0f6ae 2010 년

답변:


66

보그가 다른 진짜 이유는 서브 클래 싱에 있습니다.

보그를 서브 클래 싱하는 경우 해당 서브 클래스의 공유 상태를 명시 적으로 재정의하지 않는 한, 서브 클래스의 객체는 부모 클래스 객체와 동일한 상태를 갖습니다. 싱글 톤 패턴의 각 하위 클래스에는 자체 상태가 있으므로 다른 객체를 생성합니다.

또한 단일 패턴에서 객체는 상태뿐만 아니라 실제로 동일합니다 (상태가 실제로 중요한 유일한 것임에도 불구하고).


1
> 또한 단일 패턴에서 객체는 상태뿐만 아니라 실제로 동일합니다 (상태가 실제로 중요한 유일한 것임에도 불구하고). 그게 왜 나쁜가요?
agiliq

좋은 질문 uswaretech, 위 질문의 일부입니다. 그게 뭐가 나쁘냐?
u0b34a0f6ae 2009-08-23

2
나는 그것이 나쁜 것이라고 말하지 않았습니다. 차이점에 대한 의견이없는 관찰이었습니다. 혼란을 드려 죄송합니다. 예를 들어 드물 긴하지만 id (obj)로 개체 ID를 확인하는 경우 싱글 톤이 실제로 더 나은 경우가 있습니다.
David Raznick

그렇다면 None파이썬에서 어떻게 Borg 패턴의 예가 아닌 Singleton입니까?
Chang Zhao

@ChangZhao : None의 경우 상태를 공유 할뿐만 아니라 동일한 신원을 가져야하기 때문입니다. 우리는 x is None수표를합니다. 또한 None의 하위 클래스를 만들 수 없기 때문에 None은 특별한 경우입니다.
olivecoder

23

파이썬에서 어디에서나 접근 할 수있는 고유 한 "객체"를 원한다면 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))

산출:

하나씩 일어나는 것

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이 정의에 필요한 두 가지 기능이 있습니다.


14

그렇지 않습니다. 일반적으로 권장되지 않는 것은 파이썬에서 다음과 같은 패턴입니다.

class Singleton(object):

 _instance = None

 def __init__(self, ...):
  ...

 @classmethod
 def instance(cls):
  if cls._instance is None:
   cls._instance = cls(...)
  return cls._instance

생성자 대신 인스턴스를 가져 오기 위해 클래스 메서드를 사용합니다. 파이썬의 메타 프로그래밍은 훨씬 더 나은 방법을 허용합니다. 예를 들어 Wikipedia에있는 것 :

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 Monostate (Borg) 패턴은 Singleton보다 더 나쁩니다 (예, 가능합니다) private a = new Borg (); private 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

이것은 if이미 인스턴스가 있는지 확인 하기 때문에 Singleton에서 가능하며 , 그렇다면 무시하는 초기화없이 반환됩니다!
nerdoc

Borg init 에서도 동일한 작업을 수행 할 수 있습니다 . if __monostate: return그 후 self.foo = '바'할
볼로디미르

8

클래스는 기본적으로 객체의 내부 상태에 액세스 (읽기 / 쓰기)하는 방법을 설명합니다.

싱글 톤 패턴에서는 단일 클래스 만 가질 수 있습니다. 즉, 모든 객체가 공유 상태에 대해 동일한 액세스 포인트를 제공합니다. 즉, 확장 API를 제공해야하는 경우 단일 항목을 감싸는 래퍼를 작성해야합니다.

보그 패턴에서 기본 "보그"클래스를 확장 할 수 있으므로 취향에 맞게 API를 더 편리하게 확장 할 수 있습니다.


8

실제로 차이가있는 몇 안되는 경우에만 더 좋습니다. 당신이 하위 클래스를 할 때처럼. Borg 패턴은 매우 드문 경우입니다. 저는 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.