Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the Borg pattern better than the Singleton pattern in Python

Why is the Borg pattern better than the Singleton pattern?

I ask because I don't see them resulting in anything different.

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

What I want to display here is that the service object, whether implemented as Borg or Singleton, has a nontrivial internal state (it provides some service based on it) (I mean it has to be something useful it's not a Singleton/Borg just for fun).

And this state has to be inited. Here the Singleton implementation is more straightforward, since we treat init as the set-up of the global state. I find it awkward that the Borg object has to query its internal state to see if it should update itself.

It becomes worse the more internal state you have. For example, if the object has to listen to the Application's teardown signal to save its register to disk, that registration should only be done once as well, and this is easier with a Singleton.

like image 990
u0b34a0f6ae Avatar asked Aug 23 '09 12:08

u0b34a0f6ae


People also ask

Why singleton is not good?

By using singletons in your project, you start to create technical debt. Singletons tend to spread like a virus because it's so easy to access them. It's difficult to keep track of where they're used and getting rid of a singleton can be a refactoring nightmare in large or complex projects.

What is a disadvantage for the Singleton pattern?

Disadvantages of a Singleton PatternUnit testing is more difficult (because it introduces a global state into an application). This pattern reduces the potential for parallelism within a program, because to access the singleton in a multi-threaded system, an object must be serialized (by locking).

What is Borg pattern?

The Borg pattern (also known as the Monostate pattern) is a way to. implement singleton behavior, but instead of having only one instance. of a class, there are multiple instances that share the same state. In. other words, the focus is on sharing state instead of sharing instance.

What is a common criticism of the Singleton design pattern?

Criticism. Critics consider the singleton to be an anti-pattern as it introduces global state into an application, often unnecessarily. This in turn can place restrictions on any abstraction that uses the singleton, for example by preventing concurrent use of multiple instances.


2 Answers

The real reason that borg is different comes down to subclassing.

If you subclass a borg, the subclass' objects have the same state as their parents classes objects, unless you explicitly override the shared state in that subclass. Each subclass of the singleton pattern has its own state and therefore will produce different objects.

Also in the singleton pattern the objects are actually the same, not just the state (even though the state is the only thing that really matters).

like image 134
David Raznick Avatar answered Sep 19 '22 12:09

David Raznick


In python if you want a unique "object" that you can access from anywhere just create a class Unique that only contains static attributes, @staticmethods, and @classmethods; you could call it the Unique Pattern. Here I implement and compare the 3 patterns:

Unique

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

Output:

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 

In my opinion, Unique implementation is the easiest, then Borg and finally Singleton with an ugly number of two functions needed for its definition.

like image 36
Cristian Garcia Avatar answered Sep 17 '22 12:09

Cristian Garcia