paint-brush
Mastering the Singleton Design Pattern in APIs: When to Use and When to Avoidby@piyushtripathi
2,086 reads
2,086 reads

Mastering the Singleton Design Pattern in APIs: When to Use and When to Avoid

by Piyush TripathiMay 18th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

The Singleton Design Pattern is a way of making sure that a class only has one instance and can be accessed globally. In Python, you can do this by making a class with a private constructor and a static method that returns the instance. This is great for things like database connections or settings where you only need one instance. When it comes to testing, singletons are a big no-no. They create a tight coupling between classes.
featured image - Mastering the Singleton Design Pattern in APIs: When to Use and When to Avoid
Piyush Tripathi HackerNoon profile picture

Have you heard of the Singleton Design Pattern? It's a fancy way of making sure that a class only has one instance and can be accessed globally. In Python APIs, you can do this by making a class with a private constructor and a static method that returns the instance. This method checks if an instance already exists and gives it to you if it does, or makes a new one if it doesn't. This is great for things like database connections or settings where you only need one instance.

When should you use Singleton Pattern?

So, you know when you need to manage something that lots of different parts of your program might want to use at the same time? Like a printer spooler or a database connection? That's when you might want to use the Singleton Design Pattern in Python. 

It's also handy for keeping configuration files safe and sound. To be a Singleton, something has to tick three boxes:

  1. it needs to control access to a shared resource
  2. lots of different parts of the program need to be able to ask for it
  3. and there can only be one of them. 

A simple logger is a good example of a Singleton because it just takes information from the program and sends it to the logger. But be careful - if you use Singletons for business logic, you might end up with more than one instance.

When should you NOT use Singleton Pattern?

When it comes to testing, singletons are a big no-no. They create a tight coupling between classes, making it impossible to test one without testing the other. Plus, they're a nightmare to stub out or change references for. 

If you're designing a single-user system, using singletons might seem like a good idea, but it can really limit your scalability if you want to expand to a multi-user system. And don't even get me started on the deadlocks that can happen with multi-threaded applications. 

So, while singletons can be useful in some cases, it's important to really think about the implications and use them sparingly. Remember, they're just one tool in the design pattern toolbox.

How to Use it?

The code creates a Singleton class in Python, which ensures that only one instance of the class can be created. 

The SingleDB class is a subclass of the Singleton class and has an __init__ method that takes a table parameter. The __str__ method returns the table name. 

class SingleDB(object):    

def __init__(self, table):     	

self.table = table    def __str__(self):     	

return self.table

In the main block, two instances of the SingleDB class are created, singletonA and singletonB, both with the table name 'customer'. The id() function is used to print the memory address of each instance, and the table name is printed as well. 

singletonA = SingleDB('customer')

print( id(singletonA), singletonA.table )

singletonB = SingleDB('customer')

print( id(singletonB), singletonB.table )

Since the Singleton pattern is used, both instances have the same memory address, indicating that they are the same instance. Here are the results:

140667521864144 customer

140667521864208 customer

Alternative approach

In this approach, we check for instance existence and return the instance if it already exists:

class Singleton(object):

   def __new__(cls):

       if not hasattr(cls, 'instance'):

           cls.instance = super(Singleton, cls).__new__(cls)

       return cls.instance

Some more tips 

If you're looking to use the Singleton Pattern in Python, there are a few things to keep in mind. First off, there are three different ways to implement it: Module-level Singleton, Classic Singleton, and Borg Singleton. 

For the Borg Singleton, you can have multiple instances that share the same state, rather than just one instance. However, if you're using a module with functions, you don't really need to worry about implementing a class. 

If you do decide to use a class, keep in mind that there's no way to create private classes or constructors in Python. You'll have to rely on convention to prevent multiple instantiations. 

To implement a proper Singleton, you'll need to synchronize threads during the first creation of the Singleton object. This is important if you're controlling concurrent access to a shared resource or need a global point of access for the resource from multiple parts of the system. 

Some common use cases for the Singleton Pattern include logging classes, printer spoolers, managing database connections, file managers, and storing global states. Just remember to keep things simple and follow best practices to ensure your Singleton works as intended.

Conclusion 

The Singleton Design Pattern in Python can be a powerful tool for managing shared resources and ensuring only one instance of a class exists. However, it's important to use it sparingly and consider the implications, such as tight coupling and limitations on scalability. 

By understanding when to use and when to avoid the Singleton pattern, you can make informed decisions about your design choices and create more efficient and effective code.