El patrón de diseño Singleton 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 a la resolución de problemas específicos en diferentes dominios. Si bien existen muchas diferencias en el nivel de aplicación de nuestro software, algunos aspectos del diseño del software siguen siendo básicamente los mismos. Es posible que estos aspectos no sigan siendo los mismos para todo el software que existe, pero serán válidos para muchos escenarios. Por lo tanto, aprenderlos y comprenderlos será muy beneficioso para ayudarnos a crear programas resilientes.

    Esta es la primera 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 los patrones de diseño establecidos para todo nuestro código, sino analizar nuestras necesidades y aplicar el patrón de diseño más adecuado para 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 desde la cual se puede formular una solución.

    Sin embargo, a pesar de que los patrones de diseño pueden 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 unas pocas categorías amplias, aunque principalmente patrones de creación, patrones estructurales y patrones de comportamiento.

    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 el patrón Singleton, el método de fábrica, los patrones de fábrica abstracta, constructor y prototipo.

    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 única instancia y proporcionar un único punto de acceso global, el acceso al recurso compartido se puede restringir 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 da como resultado un código inseguro o ineficiente. Esto también nos permite acceder al mismo objeto en múltiples puntos de nuestros programas sin el temor de que pueda sobrescribirse en algún momento 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, pueden surgir problemas de integridad con el tiempo, 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 mediante la implementación de 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 singleton 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 único es que un país puede tener un solo gobierno que controle el acceso y las operaciones dentro del país. Está prohibido cualquier intento de crear otro gobierno.

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

    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 objeto único que se instanciará. Nuestro constructor verifica si hay una clase existente y genera un error.

    Al buscar el objeto con el get_instance() , comprobamos si una instancia existente está disponible y la devolvemos. Si no, creamos uno y lo devolvemos.

    Nuestra SingletonGovt en acción:

    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 uno SingletonGovt instancia almacenada en un solo punto en la memoria. Cualquier intento de crear otro gobierno se ve frustrado por la excepción que planteamos:

    Pros y contras

    Pros

    • 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 la 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, hemos presentado, discutido e implementado 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.

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *