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.
Posts relacionados:
- Los Patrones de Diseño Hoy: Patrones Creacionales
- Patrones de Reutilización de Código entre Componentes de ReactJS
- Diseño por Contrato