Mi nombre es Mariano y… finalmente, después de esa frase, puedo decir que soy programador. Desde chico que tengo amor por las computadoras, los sistemas y todo lo relacionado con la tecnología, pero la vida casi sin darme cuenta, me fue llevando por otro camino. Pero por suerte… nunca es tarde para corregir el rumbo.

Tengo 38 años, estoy enamorado de Eli y soy el padre de Joaqui, nuestro pequeño de 3 años. Trabajé desde chico en marketing y ventas en diferentes empresas e industrias, y de cada etapa me he llevado cosas muy valiosas que hoy sin pensarlo me aportan muchísimo como programador.
Hace ya más de un año que soy parte de Pigmalion Software, y me desempeño como desarrollador de software en uno de sus proyectos. Acá constantemente estamos en búsqueda de la excelencia en lo que hacemos y como parte de eso, nos capacitamos continuamente. Así fue que pensé en empezar por las bases, y escribí este pequeño documento sobre los patrones de diseño para entender un poco más que son y cómo pueden ayudarnos a la hora de programar.
¿Qué son los patrones de diseño, y cuál es su objetivo?
Según Wikipedia, “Los patrones de diseño son unas técnicas para resolver problemas comunes en el desarrollo de software y otros ámbitos referentes al diseño de interacción o interfaces.”
En otras palabras, podemos decir que los patrones de diseño son formas de hacer las cosas que otros desarrolladores descubrieron anteriormente que son efectivas para resolver los mismos problemas.
Su objetivo es proporcionar un catálogo de elementos reusables en el diseño de sistemas de software y evitar la reiteración en la búsqueda de soluciones a problemas ya conocidos y solucionados anteriormente.
Un poco de historia
En 1979, el arquitecto C. Alexander proponía en su libro “The Timeless Way of Building” el uso de una serie de patrones para la construcción de edificios de una mayor calidad. En él sostenía varios patrones, donde “cada uno describe un problema que ocurre infinidad de veces en nuestro entorno, así como la solución al mismo, de tal modo que podemos utilizar esta solución un millón de veces más adelante sin tener que volver a pensarla otra vez.”
Años más tarde, en 1987 para ser más específicos, Ward Cunningham y Kent Benk buscando mejorar y acelerar la capacitación de nuevos programadores, encontraron que existía un gran paralelismo entre el pensamiento planteado por Alexander y la arquitectura de software OO. Así fue que utilizando varias de sus ideas, desarrollaron cinco patrones de interacción hombre-ordenador que terminaron publicando en un artículo llamado: “Using Pattern Languages for OO Programs”.
Aunque este fue el principio de todo, no fue hasta mediados de los ´90, cuando los patrones tuvieron éxito en el mundo de la informática a partir de la publicación del libro “Design Patterns” creado por The gang of four compuesta por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides donde estos 5 primeros patrones terminaron siendo 23.
¿Para qué sirve un patrón de diseño?
Los patrones de diseño de software son como recetas o guías que nos ayudan a resolver problemas comunes que encontramos al diseñar y desarrollar software. Son soluciones probadas y confiables que otros desarrolladores han utilizado en situaciones similares.
Podríamos resumir los objetivos de la utilización de patrones de diseño en los siguientes, aunque no limitándose solo a estos.
- Proporcionar un catálogo de elementos reusables en el diseño de sistemas.
- Evitar la reiteración de en la búsqueda de soluciones a problemas ya conocidos y solucionados anteriormente.
- Formalizar un vocabulario común entre desarrolladores de software.
- Estandarizar el modo en que se realiza el diseño.
- Facilitar el aprendizaje a los nuevos desarrolladores.
Categorías
Existen 3 categorías para clasificar los patrones de diseño, y están basadas en su propósito.
- Creacionales: Proporcionan mecanismos de creación de objetos que incrementan la flexibilidad y la reutilización del código existente.
- Estructurales: Explican cómo ensamblar objetos y clases con estructuras más grandes a la vez que se mantiene la flexibilidad y eficiencia en la estructura.
- De comportamiento: Se encargan de generar una comunicación efectiva y una correcta asignación de responsabilidades entre objetos.
A continuación encontrarás un resumen de todos los patrones de cada categoría. Te recomiendo que profundices en la bibliografía indicada para obtener un detalle mayor de cada uno de ellos.
Patrones creacionales:
Singleton: El patrón Singleton garantiza que una clase tenga solo una instancia y proporciona un punto de acceso global a esa instancia. Esto es útil cuando se necesita tener un único objeto compartido en todo el sistema.
Factory Method: El patrón Factory Method define una interfaz para crear objetos, pero permite que las subclases decidan qué clase concreta instanciar. Esto proporciona una forma de delegar la creación de objetos a las subclases.
Abstract Factory: El patrón Abstract Factory proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas. Permite la creación de objetos relacionados entre sí sin acoplar el código a implementaciones concretas.
Builder: El patrón Builder se utiliza para construir objetos complejos paso a paso. Separa la construcción del objeto de su representación y permite que el mismo proceso de construcción cree diferentes representaciones.
Prototype: El patrón Prototype permite crear nuevos objetos clonando un prototipo existente en lugar de crearlos desde cero. Esto evita la dependencia de las clases concretas y proporciona una forma flexible de crear objetos.
Patrones estructurales:
Adapter: El patrón Adapter se utiliza para convertir la interfaz de una clase en otra interfaz esperada por los clientes. Permite que clases incompatibles trabajen juntas al envolver la interfaz de uno de los objetos.
Bridge: El patrón Bridge desacopla una abstracción de su implementación, permitiendo que ambas varíen de forma independiente. Proporciona una estructura en forma de puente entre las clases y sus implementaciones.
Composite: El patrón Composite se utiliza para componer objetos en estructuras de árbol para representar jerarquías parte-todo. Permite tratar a los objetos individuales y a las composiciones de objetos de manera uniforme.
Decorator: El patrón Decorator permite agregar comportamiento adicional a un objeto dinámicamente. Proporciona una alternativa flexible a la herencia para extender la funcionalidad de un objeto.
Facade: El patrón Facade proporciona una interfaz simplificada para un conjunto de interfaces más complejas de un subsistema. Actúa como una fachada que oculta la complejidad y facilita el uso del subsistema.
Flyweight: El patrón Flyweight se utiliza para minimizar el uso de memoria al compartir de manera eficiente objetos grandes que son comunes en una aplicación. Permite la creación de múltiples objetos livianos que representan instancias de objetos similares.
Proxy: El patrón Proxy proporciona un sustituto o representante de otro objeto para controlar el acceso a ese objeto. Actúa como una interfaz de acceso al objeto real y puede agregar funcionalidad adicional, como la verificación de permisos o el almacenamiento en caché.
Patrones de comportamiento:
Chain of Responsibility: El patrón Chain of Responsibility permite que varios objetos se turnen para procesar una solicitud. Cada objeto en la cadena tiene la opción de manejar la solicitud o pasarla al siguiente objeto en la cadena.
Command: El patrón Command encapsula una solicitud como un objeto, lo que permite parametrizar clientes con diferentes solicitudes, encolar o registrar solicitudes y soportar operaciones deshacer.
Iterator: El patrón Iterator proporciona una forma de acceder secuencialmente a los elementos de una colección sin exponer su representación subyacente. Permite recorrer una colección de objetos de manera uniforme sin conocer los detalles de implementación.
Mediator: El patrón Mediator define un objeto que encapsula cómo un conjunto de objetos interactúan. Promueve el bajo acoplamiento al evitar que los objetos se refieran explícitamente entre sí y les permite comunicarse a través de un objeto mediador.
Memento: El patrón Memento captura y almacena el estado interno de un objeto sin violar la encapsulación, de modo que el objeto pueda volver a este estado más tarde. Permite guardar y restaurar instantáneas del estado de un objeto.
Observer: El patrón Observer establece una relación uno a muchos entre objetos, de modo que cuando el estado de un objeto cambia, todos los objetos dependientes son notificados y actualizados automáticamente.
State: El patrón State permite que un objeto altere su comportamiento cuando su estado interno cambia. Define una familia de clases que representan diferentes estados y facilita la transición entre ellos.
Strategy: El patrón Strategy define una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Permite que el algoritmo varíe independientemente de los clientes que lo utilizan.
Template Method: El patrón Template Method define el esqueleto de un algoritmo en una clase base y permite que las subclases proporcionen implementaciones concretas para ciertos pasos del algoritmo. Controla el flujo general del algoritmo mientras permite que los detalles sean implementados por las subclases.
Visitor: El patrón Visitor permite agregar operaciones o comportamientos adicionales a una estructura de objetos existente sin modificar dicha estructura. Define una nueva operación (visitante) que visita objetos individuales de una estructura y realiza alguna acción basada en el tipo de objeto visitado.
Bibliografía y links recomendados:
- https://refactoring.guru/es/design-patterns
- https://es.wikipedia.org/wiki/Patr%C3%B3n_de_dise%C3%B1o
- Head First Design Patterns – Eric Freeman y Kathy Sierra