El patrón de diseño Singleton en Python

El singleton es un patrón de creación común que se utiliza para definir la creación de una única instancia y punto de acceso a un objeto. En este artículo, nos sumergiremos en el patrón de diseño Singleton, implementado en Python.

Introducción

En este artículo, nos sumergiremos en el Patrón de diseño Singleton, implementado en Python.

A medida que pasa el tiempo, el software se adapta más para resolver problemas específicos en diferentes dominios. Si bien hay muchas diferencias en el nivel de aplicación de nuestro software, algunos aspectos del diseño del software siguen siendo prácticamente los mismos. Es posible que estos aspectos no sigan siendo los mismos para todo el software, pero serán válidos para muchos escenarios. Por lo tanto, aprenderlos y comprenderlos será muy beneficioso para ayudarnos a construir programas resilientes.

Este es el primero de una serie sobre Patrones de diseño en Python y los diferentes patrones que podemos utilizar para crear software.

¿Qué es un patrón de diseño?

Un patrón de diseño es un enfoque particular para resolver un problema recurrente en el desarrollo de software y también se utiliza para representar buenas prácticas. No es un código real, pero representa una forma particular de organizar el código para producir la solución deseada de la manera recomendada. Esto significa que no tenemos que seguir estrictamente patrones de diseño establecidos para todo nuestro código, sino analizar nuestras necesidades y aplicar el patrón de diseño que mejor se adapte a nuestras necesidades.

Los patrones de diseño surgen de una gran experiencia en la resolución de problemas en el desarrollo de software y se prueban y prueban para adaptarse a escenarios particulares. Otra razón para aprender sobre los patrones de diseño es que, si bien un patrón puede no funcionar para un escenario en particular, puede ofrecer una base a partir de la cual se puede formular una solución.

Sin embargo, por mucho que los patrones de diseño puedan ayudarnos a salir de varias situaciones, es importante evaluar la situación actual y explorar todas las opciones disponibles antes de saltar directamente a un patrón porque puede haber una solución mejor.

Los patrones de diseño se dividen en algunas categorías amplias, aunque principalmente patrones de creación, patrones estructurales y patrones de comportamiento.

Patrones de creación {#patrones de creación}

Hay varios aspectos de los patrones de diseño que los distinguen entre sí, incluida la complejidad del patrón de diseño, el nivel de aplicación dentro de un sistema y la cantidad de detalles.

Los patrones de creación incluyen aquellos que definen formas de crear objetos que contribuyen a una mayor flexibilidad y reutilización del código en toda la aplicación.

Los ejemplos de patrones de creación incluyen los patrones Singleton, Factory Method, Abstract Factory, Builder y Prototype.

El patrón Singleton

Definición

El patrón singleton es un patrón de creación común que se utiliza para definir la creación de una única instancia de una clase al tiempo que proporciona un único punto de acceso global a ese objeto.

Este patrón restringe la cantidad de objetos que se pueden crear a partir de una clase a un solo objeto que, a menudo, se compartirá globalmente en una aplicación.

Motivación

Este patrón se implementa comúnmente en funciones que requieren control sobre el acceso a un recurso compartido, como una conexión de base de datos o un archivo. Al garantizar que una clase solo se pueda usar para crear una sola instancia y proporcionar un único punto de acceso global, se puede restringir el acceso al recurso compartido y se puede mantener la integridad.

La creación de instancias únicas también ayuda a garantizar que algunos aspectos de nuestros programas no puedan ser sobrescritos por otras clases, lo que resulta en un código inseguro o ineficiente. Esto también nos permite acceder al mismo objeto en múltiples puntos de nuestros programas sin temor a que se sobrescriba en algún punto de nuestro programa.

Por ejemplo, las conexiones a la base de datos se realizan una vez en nuestros programas, y el mismo objeto se utiliza para realizar operaciones en nuestra base de datos en toda la aplicación. Si diferentes partes de nuestra aplicación pudieran crear sus propias conexiones de base de datos, con el tiempo podrían surgir problemas de integridad, ya que cada parte intenta acceder a la base de datos por su cuenta.

Implementación

El patrón Singleton requiere que la instanciación de una clase esté restringida a un solo objeto. El control de la creación de objetos se logra implementando un método de creación que guarda el objeto creado en un campo estático.

Todas las llamadas a este método de creación devuelven el objeto único original o un error que indica la existencia de un objeto instanciado. Esto evita la creación de más de un objeto para nuestra clase y mantiene la propiedad singleton.

Una buena analogía de un patrón singleton es que un país puede tener un solo gobierno que controle el acceso y las operaciones dentro del país. Cualquier intento de crear otro gobierno está prohibido.

Podemos implementar esta analogía del gobierno en una clase singleton de la siguiente manera en Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class SingletonGovt:
   __instance__ = None

   def __init__(self):
       """ Constructor.
       """
       if SingletonGovt.__instance__ is None:
           SingletonGovt.__instance__ = self
       else:
           raise Exception("You cannot create another SingletonGovt class")

   @staticmethod
   def get_instance():
       """ Static method to fetch the current instance.
       """
       if not SingletonGovt.__instance__:
           SingletonGovt()
       return SingletonGovt.__instance__

En nuestro ejemplo, definimos la variable que contendrá el único objeto que se instanciará. Nuestro constructor comprueba si existe una clase existente y genera un error.

Cuando buscamos el objeto usando el método get_instance(), verificamos si una instancia existente está disponible y la devolvemos. Si no, creamos uno y lo devolvemos.

Nuestro SingletonGovt en acción:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
government = SingletonGovt()
print(government)

same_government = SingletonGovt.get_instance()
print(same_government)

another_government = SingletonGovt.get_instance()
print(another_government)

new_government = SingletonGovt()
print(new_government)

Cuando ejecutamos nuestro script, podemos ver que solo tenemos una instancia SingletonGovt almacenada en un solo punto en la memoria. Cualquier intento de crear otro gobierno se ve frustrado por la excepción que planteamos:

patrón de diseño singleton en resultados de python

Ventajas y desventajas

Ventajas

  • El patrón Singleton ofrece la garantía de que solo existe una instancia de nuestra clase y reduce el riesgo de comportamiento inesperado en nuestro programa.
  • Dado que la creación de la clase está controlada por una sola clase, esto ofrece flexibilidad ya que solo es necesario realizar cambios en una clase y un objeto.

Contras

  • Una clase creada con el patrón singleton viola el Principio de responsabilidad única ya que la clase puede tener que manejar más de una responsabilidad en un momento dado.
  • La gestión del ciclo de vida puede plantear problemas en otras áreas, como las pruebas, ya que la clase singleton se mantiene viva durante la vida útil de la aplicación y diferentes casos de prueba pueden requerir nuevas versiones de la clase.

Conclusión

En esta publicación, presentamos, discutimos e implementamos el patrón de diseño Singleton.

Al igual que cualquier otro patrón de diseño, tiene sus pros y sus contras y, si bien puede ser adecuado para algunas situaciones, es posible que no se aplique a todas nuestras necesidades de desarrollo. Por lo tanto, depende de nosotros analizar el problema en cuestión y tomar la decisión de si el patrón singleton facilitará o no nuestro trabajo.