Los Patrones de Diseño Hoy: Patrones Estructurales

Estoy dedicando esta serie de post a ver cómo han resistido los patrones de diseños clásicos, los del libro original de la GoF, el paso del tiempo. En el anterior post hablábamos sobre los patrones de diseño creacionales, y en éste le toca el turno a los patrones de diseño estructurales.

Adapter

Un patrón que tiene como finalidad «convertir» el API de una clase en la de otra resulta útil, claro, cuando tienes varias clases con distintas APIs que necesitas homogeneizar. ¿Cómo de frecuente es eso? Depende de lo que estés haciendo.

En la época en la que me tocó tratar con muchos dispositivos hardware era bastante habitual. Hoy en día se utiliza en casi todas las librerías multiplataforma para salvar las distancias entre distintas APIs nativas. Xamarin Forms, los plugins de Apache Cordova, o las implementaciones del (¿extinto?) OWIN para distintos hosts, son un buen ejemplo de ello.

Utilidad hoy en día: 3.

Bridge

Creo que no he implementado este patrón jamás. Diría que ni siquiera lo he usado y, sinceramente, no se me ocurren muchos escenarios donde aplicarlo. De hecho, si alguien lo ha usado alguna vez y me cuenta el escenario, se lo agradecería mucho.

La idea de poder desacopar una abstracción y su implementación para poder evolucionar ambas por separado me parece tan enrevesada que, como en el caso del Abstract Factory, estoy casi seguro de que siempre se puede encontrar una forma más sencilla de hacerlo.

Utilidad hoy en día: 1.

Composite

Quizá no sea tan frecuente en la parte de «dominio» de las típicas aplicaciones de línea de negocio, pero aun así es fácil encontrártelo en la vida real y funciona bien.

El 90% de las veces que te encuentras con una estructura jerárquica de cosas, está implementada siguiendo un patrón composite. Lo puedes ver en los controles de los típicos frameworks de GUI (Windows Forms, XAMLs variados, Swing), los componentes de React, muchos DOMs (como XmlDocument/XDocument en .Net o HTML en Javascript)…

Utilidad hoy en día: 3.

Decorator

Siempre ha sido uno de mis patrones preferidos. Lo considero una forma sencilla y elegante de extender el comportamiento de una clase (o incluso de una función), así que suelo intentar propiciar diseños donde sea fácilmente aplicable. Diseños del estilo del vetusto Agatha o del más actual Mediatr se prestan muy bien a combinarlos con este patrón, porque al tener un único punto centralizado por el que pasa todo el proceso de la aplicación, utilizar decoradores para añadir comportamiento es muy fácil.

Te lo puedes encontrar en multitud de librerías, como por ejemplo en ASP.NET MVC Core, donde el pipeline de ejecución es poco más que una cadena de funciones decorando funciones. En general, casi siempre que veas algo llamado middleware es probable que tenga por detrás este patrón, como pasa con express, ring o redux.

Utilidad hoy en día: 4.

Facade

Muy útil. Quizá porque cada vez tendemos a complicar más las cosas. O porque las hacemos «mejor» y separamos todo en cuatrocientas mil clases pequeñas con responsabilidades perfectamente definididas pero muy difíciles de coordinar entre sí.

El caso es que simplificar el uso de un paquete o de un conjunto de clases siempre viene bien. Cuanto más fácil de usar es algo, más difícil es equivocarse al utilizarlo. Es un patrón que utilizo bastante, incluso en su versión estática.

Utilidad hoy en día: 5.

Flyweight

Este patrón engaña un poco. En la descripción original se hace mucho hincapié en reducir el uso de memoria compartiendo instancias de objetos para evitar crear varios objetos con los mismos valores. Si vas por esa línea, igual te cuesta reconocerlo.

Si piensas que en él como una caché que te devuelve los mismos objetos una y otra vez sin necesidad de crearlos (lo que podría ser costoso si, por ejemplo, hubiera que obtenerlos de una base de datos), seguramente ya te resulte más familiar y habitual.

Hay que tener en cuenta que los objetos que se crean al usar este patrón necesitan ser inmutables (para ser compartidos sin problemas). De hecho, otro caso que podríamos considerar una variante de este patrón son las estructuras de datos inmutables típicas de lenguajes funcionales (que también mencionamos en el anterior post como una variación de prototype).

Utilidad hoy en día: 4.

Proxy

Otro patrón, como Bridge, que creo que nunca he implementado a mano. Sin embargo, sí que he usado Proxies. Y muchos. Desde los proxies de los servicios web y de remoting de principios de los 2000, a los generados por librerías como Rhino.Mocks para tests, pasando por los que usan los ORMs para lazy load o incluso proxies generados usando Dynamic Proxy.

Pese a su utilidad, lo que menos me gusta de este patrón es el componente de magia que introduce. La idea de poder crear un objeto que se hace pasar por otro que pero realmente no es el otro, muchas veces acaba dando lugar a abstracciones incorrectas que hubiera sido mejor hacer explícitas.

Utilidad hoy en día: 3.

Conclusión

Al igual que los patrones creaciones, creo que los patrones estructurales gozan hoy en día de buena salud.

Algunos de ellos, como Decorator o Flyweight, encajan muy bien con el movimiento hacia la programación funcional que se está dando en los últimos años: envolver una función en otra es una forma muy natural de añadir comportamiento, y las estructuras de datos inmutables se prestan perfectamente a ser compartidas entre distintos componentes.

Bridge sigue siendo para mi un misterio, y Proxy, que en su momento me pareció una buena idea, ha perdido parte de mi cariño por el aspecto mágico que conlleva.

3 comentarios en “Los Patrones de Diseño Hoy: Patrones Estructurales

  1. Seguramente has usado el patrón Bridge más de una vez, cuando la implementación que vas a usar es temporal, no vas a querer que tu código esté acoplado a la abstracción temporal (la hagas tú o uses una existente) por lo que básicamente tomarás la temporal, cogerás lo que crees que te viene bien ahora y la pondrás en el bridge. Como yo veo los patrones como meras curiosidades quizás estoy haciendo una interpretación demasiado a la ligera, pero suelo hacer eso con relativa frecuencia, pues permite centrarme en la estructura general sin invertir apenas tiempo en detalles que seguramente cambiarán hasta cierta maduración. Suele haber *mucha* diferencia entre definir (y usar) el bridge a usar directamente la temporal «y ya refactorizaré» (pues seguramente será tarde al tener la implementación acoplada a la temporal). Otro uso que se me ocurre es si tienes un codebase penoso y sin tener tiempo a refactorizar has de hacer algún evolutivo, quizás pudieras acoplar el evolutivo a un bridge que tira de legacy, etc.

    Los Proxys para mí son justo lo contrario, tienes una bonita abstracción y pones algo en medio que la mierdea de lo lindo (ej. las típicas para hacer «inmutables» objetos que no lo son), puedes llamarlo «magia» si quieres pero en mi opinión son ñapas (hacks) en toda regla.

    Resulta entretenida esta serie de posts, aunque me parece que las notas están un poco sesgadas ;P cierto que no suelo prestar mucha atención a los patrones más allá del concepto general (en lo cual reconozco que me pierdo algo pero bueno, lo sobrellevo bien).

  2. Coincido contigo en buscar una interpretación más «liberal» de los patrones. Al final es más una cuestión de ideas que de seguir a rajatabla un diagrama UML.

    Las notas no están un poco sesgadas: están totalmente sesgadas ;-)

  3. Creo que los que menos conozco es el adapter y el bridge, los demas son casí por ley que algunas vez los haz escuchado cuando trabajas con Java EE, los proxys siempre cuesta trabajo explicarlos a los nuevos y normalmente no preguntan hasta que les pasa un «org.hibernate.LazyInitializationException – could not initialize proxy – no Session» pero su utilidad es mucha, al menos en Hibernate.

    Excelente articulo.

Comentarios cerrados.