El singleton es un patrón de diseño ampliamente utilizado en el desarrollo de software. Sin embargo, a pesar de su popularidad, a menudo es considerado como un antipatrón. ¿Esto realmente es así? ¿Se trata de un patrón de diseño funcional o no? En esta oportunidad te lo explico.
Sin lugar a dudas este patrón ha tomado mucha popularidad en los últimos tiempos, pero esto no indica que sea bueno o malo, simplemente muestra que ha dado mucho de qué hablar.
A través del patrón de diseño de singleton, la clase garantiza que solo se instancia una vez, y por ello se puede proporcionar un fácil acceso a esta instancia única. Entonces, ¿Por qué muchas personas lo consideran negativo y otras positivo? Descúbrelo a continuación.
¿Qué son los singleton?
En primer lugar, es conveniente comenzar con una descripción general de este patrón, para que sepas con exactitud de qué se trata.
A veces, al codificar, se necesita el concepto de objeto global. Este es un objeto que solo tiene una instancia en la aplicación, y algunos ejemplos de esto son: Cola de impresión, sistema de archivos y administrador de ventanas.
Este patrón de diseño hace que la clase sea responsable de su propia creación, y controla el acceso a la instancia, para que así su naturaleza de “instancia única” no se pueda alterar. Por lo tanto, con dicho patrón puedes asegurarte de que el objeto nunca se cree más de una vez.
Adicionalmente, contiene variables estáticas, las cuales pueden acomodar instancias únicas y privadas de sí mismas. Debes saber que es utilizada en aquellos escenarios en donde el usuario desea restringir el proceso de instanciación de una clase únicamente a un objeto, lo cual es útil cuando se necesita de un solo objeto para coordinar todas las acciones de un sistema.
Luego de saber qué es este patrón, es importante que sepas que puede y debe haber solo una instancia para este los objetos globales.
¿Dónde se utiliza este patrón?
Este tipo de patrón se usa generalmente en lenguajes de programación, tales como Java y .NET, para definir una variable global. De esta forma un solo objeto es utilizado en todos los sistemas, por lo que permanece constante, y se define una sola vez, en lugar de varias veces como sucede con otros patrones.
Ejemplos modernos de objetos que pueden usarse con este patrón
Para comprender realmente qué es o de qué se trata este patrón y cómo es útil, es necesario considerar algunos ejemplos más modernos de objetos que se pueden representar bien con dicho patrón.
Proveedor de diálogo
Un buen ejemplo es el proveedor de diálogo. Una aplicación basada en la interfaz de usuario puede mostrar cuadros de diálogo para recopilar información del usuario.
Tiene sentido que en ese caso solo tengas una instancia de tu proveedor de diálogo, para que puedas controlar cómo se usa. Por ejemplo, es probable que quieras aplicar solo un cuadro de diálogo en la pantalla a la vez.
Repositorio de entidades
Otro ejemplo que podría resultar atractivo es este. Casi todas las aplicaciones necesitan algún tipo de almacenamiento de datos, y esto a menudo se implementa mediante el patrón de repositorio.
Puede ser muy tentador almacenar tus objetos usando el patrón de los singleton, para que sean fácilmente accesibles desde cualquier lugar del código.
Además, esto no es solo por conveniencia: Tener una instancia única del repositorio de entidades significa que tienes un lugar para implementar el almacenamiento en caché para tus entidades, y puedes lograr que las cargas de datos posteriores no tengan que ir al sistema de archivos o a la base de datos.
Dependencias de cableado(Wiring dependencies)
Tradicionalmente, al conectar las dependencias a través de tu base de código, tienes dos opciones:
- Conectar las dependencias a lo largo de tu estructura de código potencialmente anidada
- Acceder directamente a la dependencia como un objeto global
La primera opción es tediosa y lenta, y este cableado dificulta la reestructuración de tu aplicación. La segunda opción, que es acceder directamente a un objeto global, es mucho más fácil, pero, nuevamente, dificulta la reestructuración de la aplicación.
Sin embargo, podría decirse que la segunda opción es mejor, ya que aunque ambas alternativas conducen a un código cableado que es difícil de modificar, esta última es más fácil de instalar, y existirá menos cableado para cambiar más adelante, porque no será necesario pasarlo a través de todas las capas intermedias.
Pero los globales son malos, ¿verdad? Bueno, no tanto en los días en que se inventó el singleton.
En aquel entonces, los programas de computadora no eran tan grandes y complicados como lo son ahora, y las pruebas automatizadas eran raras. El patrón de diseño singleton introduce control sobre el acceso al tiempo que conserva la conveniencia de tener acceso directo desde cualquier lugar de nuestra base de código. Hasta cierto punto, el patrón de diseño singleton legitimó el uso de objetos globales.
¿Por qué son populares?
Con el paso de los años, los programas informáticos se hicieron cada vez más grandes y complejos. Al mismo tiempo, los equipos que los desarrollaron crecieron, y las pruebas automatizadas ganaron fama.
Este patrón de diseño es tan popular debido a que cuando se lanzó, fue usado en exceso, y de hecho, se utilizó de forma incorrecta. Los problemas con dicho patrón dieron mucho de qué hablar, y se manifestaron hasta el punto en que muchas personas lo empezaron a conocer como un antipatrón.
Sin embargo, esto sucedió debido a que se entendió que usar este patrón por si solo es menos conveniente que acceder directamente a un objeto global, debido a que implica los siguientes inconvenientes:
- Los objetos que dependen del patrón no se aíslan fácilmente para realizar pruebas
- El código base está cableado y no es fácil reestructurarlo
Es por este motivo que muchas personas empezaron a criticarlo y tomó una popularidad negativa en general, aunque realmente se debe a que fue y es usado aun de una manera incorrecta.
Sin embargo, la realidad es que este patrón es bastante bueno, y sin duda eso explica por qué muchas personas aún lo usan. Para usarlo, y aun así poder realizar pruebas automatizadas y disponer de una arquitectura que sea susceptible de reestructuración, se deben tomar en cuenta cosas como:
- La clase en sí misma no debería ser responsable de su propia creación
- Otras clases no deben estar vinculadas a este patrón
Resolver estos problemas no es tan difícil, pero lo que realmente necesitas para que sea conveniente es que el cableado de las dependencias sea automático. No quieres tener que pasar por una dependencia a lo largo de tu base de código para que esté en todos los lugares a los que se debe acceder.
Usar Inyección de dependencia para evitar el mal uso de singleton
La inyección de dependencia es un patrón de diseño que llegó un poco más tarde, y sin lugar a dudas salva por completo el panorama de los singletons. La razón de esto es que, en conjunto, ambos son capaces de brindar la conveniencia de los últimos, sin ningún tipo de remordimiento o culpa.
Esta inyección de dependencia automática también es conocida como inversión de control, y automatiza la creación y el cableado de tus dependencias.
Conexión de objetos globales
Puedes usar la inyección de dependencia para conectar tus objetos globales a través de tu base de código, sin tener que realizar ninguna configuración manual. Esta automatización hace que sea trivial reescribir y reestructurar las conexiones entre componentes en la aplicación, incluso cuando esas conexiones son para el otro patrón de diseño.
Cuando se inyecta una dependencia en un objeto, ese objeto no necesita saber que en realidad está conectado al patrón de diseño del que hablamos. Luego, para las pruebas automatizadas, se inyecta otro objeto simulado como dependencia, en lugar del objeto real. Esto lo que significa es que puedes hacer pruebas automatizadas contra objetos que dependen del patrón de diseño mencionado.
Orden de inicialización
Por otra parte, la inyección de dependencia automatizada también determina el orden de inicialización de tu aplicación. De forma automática instancia las dependencias y las sub dependencias, y las crea en el orden correcto y en el momento adecuado, justo antes de que se necesiten.
Conclusión
Si bien los singleton se han considerado durante mucho tiempo un patrón de diseño “antipatrón”, la realidad es que se debe tomar en cuenta que existen muchas opiniones diversas en ese sentido, ya que en cuanto a los patrones de diseño, y en general, no es igual la visión de una persona que la de otra.
Adicionalmente, todos los patrones de diseño pueden ser aplicados en situaciones incorrectas, y es por este motivo que, en su mayoría, se llegan a convertir en antipatrones para las personas. También, sin lugar a dudas, los patrones que se usan de forma incorrecta o en exceso pueden causar daños graves.
Es por este motivo que cuando se habla de este tema se debe comprender que no todo es blanco y negro, ya que también existen muchas tonalidades de gris.
Debemos ser sinceros, la codificación es difícil. Cada patrón de diseño, cada técnica, cada buena práctica se puede usar de manera incorrecta, y por ende, es posible abusar de cada uno de ellos, y lógicamente este patrón no es una excepción.
Por ello, podría decirse que este patrón de diseño ha sido muy usado y aplicado de una manera errónea, y es por eso que ha recibido tantas críticas negativas por parte de las personas.
¿Qué te pareció este articulo? Singleton: ¿patrón or antipatrón de diseño? Dejame tu comentario y no te olvides de compartirla 😄