¿Qué son los patrones de diseño?
Los patrones de diseño o design patterns son soluciones a problemas recurrentes que nos encontramos durante el desarrollo de software. Nos sirven para solucionar problemas que se repiten en la etapa del desarrollo de software.
Al final son una forma estándar de solucionar problemas de diseño que ya han sido probados y que funcionan
Tipos de patrones de diseño
Existen tres tipos de patrones, que son:
- Creacionales: Aquellos que nos ayudan durante la creación de objetos.
- Estructurales: Los que nos ayudaran en como estructurar o de que forma se componen los objetos.
- Comportamiento: Son aquellos que nos ayudan en como los objetos se comunican o comportan entre ellos.
Patrones creacionales
Factory o Factory Method
Imagina que quieres desarrollar una aplicación de logística para gestionar la entrega de paquetes y que por ahora solo realizas entregas por carretera. Por lo tanto tu aplicación solo instancia clases de tipo Camión.
¿Pero que ocurre si mañana entregas paquetes a otros continentes? Tendrías que revisar toda tu aplicación para añadir esta nueva clase Barco.
El patrón Abstract Factory propone que en lugar de crear estos objetos directamente los crees a través de objeto llamado «fabrica«.
De esta forma si en el futuro entregas paquetes a través de la clase Avión solo modificarías la «fabrica» sin necesidad de realizar modificaciones en el resto del código.
Tenemos una explicación muy bien detallada en https://refactoring.guru/es/design-patterns/factory-method
Builder
Para este caso vamos pensar que desarrollamos un portal de venta de un coche con muchos modelos distintos para un mismo coche. Por ejemplo podemos seleccionar el modelo clásico, deportivo, exhibición, futurista, etc.
¿Crearíamos una clase coche con todas las posibilidades existentes? ¿No seria una clase demasiado grande y compleja?
Aquí es donde el patrón builder nos ayuda, el patrón builder nos dice que en lugar de tener una sola clase tengamos varias clases llamadas constructoras con cada uno de los modelos y una clase directora que sera la que utilizaremos para crear el coche.
De esta forma si queremos añadir un nuevo modelo a nuestro coche nos sera mucho mas sencillo añadiendo un nuevo constructor en lugar de modificar una clase única que seguramente quedaría llena de sentencias if.
Una explicación mas detallada en https://refactoring.guru/es/design-patterns/builder
Abstract Factory
Vamos a pensar en nuestro primer ejemplo de empresa de logística pero en este caso vamos a gestionar a la vez varias empresas de logística donde cada una tiene su propia imagen. Por ejemplo seur, ups y dhl.
Dependiendo de la empresa contratada vamos a necesitar un camión, barco o avión con la imagen de seur, ups o dhl. Con el método Factory tenemos solucionado como crear el transporte pero ahora tenemos la complejidad de la marca o imagen.
Podríamos usar tres veces el patrón Factory pero tendríamos que comprobar en cada caso la imagen que queremos obtener para saber cual de las tres «fabricas» debemos utilizar.
El patrón Abstract Factory nos ayuda con este problema, nos dice que tengamos una «fabrica» común y que por debajo derive a la fabrica correspondiente la responsabilidad.
De esta forma al añadir una nueva empresa o marca solo debemos crear una nueva «fabrica» y modificar la «fabrica» común.
Más información en https://refactoring.guru/es/design-patterns/abstract-factory
Prototype
Imagina que estamos desarrollando una aplicación tipo Paint de windows y tenemos que implementar el famoso copia y pega.
Para este caso nos seria muy útil poder copiar el objeto que se ha seleccionado para luego insertarlo, ¿Pero como sabemos que tipo de objeto ha seleccionado?
En este caso el patrón Prototype es la solución, nos dice que debemos tener una interfaz común con el método clonar y que deben utilizar todos aquellos objetos que puedan ser clonados.
De esta forma evitamos acoplar el código de nuestro programa a tener que conocer las clases que trabajamos. Si mañana queremos clonar un nuevo objeto no tenemos que modificar todo el código anterior.
Tenemos mucha mas información en https://refactoring.guru/es/design-patterns/prototype
Singleton
Imagina que estamos desarrollando un editor de texto y vamos a implementar la funcionalidad de imprimir el documento.
Si cada vez que imprimimos un documento creamos el objeto es posible que al intentar imprimir dos documentos en un periodo muy corto de tiempo el segundo documento no se pueda imprimir porque la impresora esta ocupada.
¿Entonces que hacemos? ¿Implementamos toda la lógica para tratar estos errores? Imagina que queremos imprimir 100 documentos. ¿Tiene sentido tener 100 objetos creados todos preguntando a la impresora si esta libre o no? ¿No sería más sencillo tener una sola cola de impresión?
El patrón Singleton nos da una forma de tener un objeto único en toda nuestra aplicación por lo que en lugar de tener 100 objetos intentando imprimir 100 documentos tendríamos un único objeto con 100 documentos a imprimir.
Con el patrón Singleton cada vez que intentamos crear el objeto nos devuelve el objeto en su estado actual en caso de exisitir y si nunca fue creado
Mas detalles en https://refactoring.guru/es/design-patterns/singleton