Почему шаблон Борг лучше, чем шаблон Синглтон в Python - PullRequest
72 голосов
/ 23 августа 2009

Почему шаблон Борг лучше, чем шаблон Singleton ?

Я спрашиваю, потому что я не вижу их в результате чего-то другого.

Borg:

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

Singleton:

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 / Борг просто для удовольствия).

И это состояние должно быть инициировано. Здесь реализация Singleton более проста, так как init мы рассматриваем как настройку глобального состояния. Я нахожу неловким, что объект Borg должен запросить свое внутреннее состояние, чтобы увидеть, должен ли он обновляться сам.

Становится хуже, чем больше у вас внутреннего состояния. Например, если объект должен прослушивать сигнал разрыва Приложения, чтобы сохранить свой регистр на диск, эту регистрацию также следует выполнить только один раз, а с Singleton это проще.

Ответы [ 6 ]

55 голосов
/ 23 августа 2009

Реальная причина того, что borg отличается, сводится к подклассам.

Если вы создаете подкласс borg, объекты подкласса имеют то же состояние, что и объекты их родительских классов, если вы явно не переопределите общее состояние в этом подклассе. Каждый подкласс одноэлементного шаблона имеет свое собственное состояние и, следовательно, будет создавать различные объекты.

Также в шаблоне синглтона объекты на самом деле одинаковы, а не только состояние (хотя единственное, что действительно имеет значение - это состояние).

19 голосов
/ 28 декабря 2013

В python, если вам нужен уникальный «объект», к которому вы можете получить доступ из любого места, просто создайте класс Unique, который содержит только статические атрибуты, @staticmethod s и @classmethod s; Вы могли бы назвать это Уникальным Образцом. Здесь я реализую и сравниваю 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

#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

#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

Test

#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

На мой взгляд, уникальная реализация - самая простая, затем Борг и, наконец, Синглтон с ужасным количеством двух функций, необходимых для ее определения.

13 голосов
/ 23 августа 2009

Это не так. Обычно не рекомендуется использовать такой шаблон в 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()
8 голосов
/ 23 августа 2009

Это лучше только в тех немногих случаях, когда у вас есть разница. Как, когда вы подкласс. Паттерн Борг чрезвычайно необычен, я никогда не нуждался в нем по-настоящему за десять лет программирования на Python.

8 голосов
/ 23 августа 2009

Класс в основном описывает, как вы можете получить доступ (чтение / запись) к внутреннему состоянию вашего объекта.

В шаблоне синглтона у вас может быть только один класс, т. Е. Все ваши объекты предоставят вам одинаковые точки доступа к общему состоянию. Это означает, что если вам нужно предоставить расширенный API, вам нужно написать оболочку, обернутую вокруг синглтона

В шаблоне borg вы можете расширить базовый класс "borg" и тем самым более удобно расширить API на ваш вкус.

1 голос
/ 24 октября 2017

Кроме того, шаблон, подобный 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 = ..
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...