Como ya veníamos viendo en algunos lunes anteriores, UML es un lenguaje que nos permite modelar practicamente cualquier sistema, no solamente aquel que vayamos a implementar, sino que sirve para modelar prácticamente todo.
Por lo general, la estructura de los sistemas tienden a repetirse, y gracias a ello se empezaron a ver que ciertos “patrones de diseño” comenzaban a repetirse también.
Según los arquitectos de software, los patrones de diseño están en todas partes y probablemente los hayas usado sin saberlo. Hay muchos artículos que tratan sobre estos y su uso en contextos muy simples. Hoy traigo cinco de ellos…
Los patrones de diseño a veces pueden parecer magia vudú: según el idioma que use, la implementación puede ser muy diferente. Sin embargo, en un nivel alto, todo suena más claro: los diagramas ayudan mucho a entender las cosas (no se puede negar).
5 patrones de diseño en un diagrama de clase UML
Cuando diseñamos nuestra computadora, asumimos que:
- una computadora está hecha de un procesador, una memoria y posibles interfaces adicionales (sonido … etc.),
- un procesador es parte del “cerebro de la compu”, pero también puede ser parte de alguna interfaz (como la placa de video que tiene su propio procesador, por ejemplo)
- un procesador tiene la capacidad de leer/escribir en la memoria, cargar un programa en una dirección y ejecutarlo.
- una memoria puede ser una RAM o una caché,
- un caché siempre trata con una RAM,
- si existe una caché, es usada principalmente por el procesador,
- una computadora puede manejar directamente hasta 3 tarjetas o interfaces adicionales,
- para manejar nuevas tarjetas, una computadora debe tener una tarjeta de extensión o expansión,
- y agregamos que existen muchas tarjetas de sonidos con diferentes.
La solución que encontramos es la siguiente (reducido para este ejemplo):

Vamos de movida a ver que patrones aparecen:
El patrón proxy
Primero, comencemos con uno simple: el patrón proxy. Lo usamos para diseñar los elementos de RAM / caché.

La idea principal detrás de este patrón es usar un intermediario, que es exactamente lo que sucede cuando el procesador necesita leer algo en la memoria. Cuando el procesador intenta leer en la memoria, solo realiza una operación de lectura (@). Si hay una memoria caché presente, la memoria caché ve dentro del fragmento de bytes que obtuvo. Si la dirección no está allí: lee en la memoria RAM, busca un nuevo fragmento de memoria y le da el byte de lectura al procesador. Este flujo es invisible para el procesador ya que el proxy le da acceso al objeto oculto cuando es necesario. El patrón de proxy tiene muchos usos (cambia el comportamiento de algunas operaciones, restringe la visibilidad de las operaciones, el acceso diferido a los objetos …) pero la idea es siempre la misma: un proxy es una especie de intermediario.
El patrón Composite
Este patrón es realmente útil cuando tiene que definir objetos tipados recursivos. ¿Alguna suposición acerca de qué parte de la máquina lo necesita?

Esto es una recursión compuesta. Nuestra computadora solo puede administrar 3 tarjetas adicionales. Sin embargo, puede usar una ExtensionBoard que permitirá el uso de otras tarjetas. En realidad, esta ExtensionBoard puede contener y reunir muchas Tarjetas y, por qué no, otra ExtensionBoard que permitirá a la computadora usar otras. Composite modela así la recursión.
El patrón Adapter
Mantengámonos en el área de la Tarjeta y las cosas de nuestra computadora para hablar sobre SoundCards. Como dije en la introducción, muchos proveedores diseñan SoundCards para computadoras:

Tener múltiples elecciones sobre nuestra SoundCard es agradable. Sin embargo, incluso si están en la misma página sobre la forma en que debería funcionar la tarjeta, no usan una interfaz común y proporcionan diferentes operaciones que tienen casi la misma semántica. En este contexto, los adaptadores son un tipo de convertidores de socket que envolverán al proveedor de tarjetas de sonido e implementarán la interfaz común al delegar el comportamiento a la tarjeta envuelta. Por ejemplo, Vendor2Adapter implementa el método end () delegando su ejecución al método halt () del elemento Vendor2Sound.
El patrón Decorator
Detallamos cómo la memoria y las tarjetas son manejadas por nuestra computadora. Ahora, nos concentraremos en el procesador. Nuestro procesador puede obtener un impulso mediante el uso de Tarjetas aceleradoras. ¿Cómo modelamos esto?

Nuestro procesador siempre debe tener el mismo comportamiento. Pero nos gustaría agregarle un nuevo comportamiento sin perturbar su proceso original. El patrón decorator es, por lo tanto, un gran candidato. Agrega un comportamiento adicional para la fase de inicialización y la fase de ejecución. La implementación o la FastCard muestra que cuando se llama al método init (), la tarjeta llama primero al método adicionalInit (), luego llama al método init () de la CPU que decora (bueno, en este caso, la diferencia entre el el patrón proxy y el patrón decorator es la delgadación, por cierto, algunas personas lo llaman ‘proxy inteligente’). Lo mismo se realiza para el método execute ().
El patrón Facade
Finalmente, el patrón “principal” aquí, el patrón de la fachada. Este patrón se usa aquí en el elemento Máquina:

El objetivo principal del patrón facade es ocultar la complejidad de un sistema al proporcionar métodos fáciles y comprensibles. En nuestro caso, el método execute () de Machine Element nos permite ejecutar un programa dedicado. La forma en que se ejecuta la ejecución del programa es bastante compleja. El procesador debe iniciarse así como las tarjetas adicionales. Luego, el programa que debe ejecutarse debe cargarse y ubicarse en la memoria en una dirección específica. El método execute () oculta toda esta complejidad al organizar todas las inicializaciones / inicializaciones de objetos y al agregar todos los valores mágicos requeridos. Este patrón se usa casi todo el tiempo cuando los sistemas complejos necesitan ser manejados simplemente.
Wow, y sólo vimos cinco de los patrones… Seguroles pasa como a mí, ya están pensando encómo modificar modelados viejos con este nuevo conocimiento.