El hilo de los patrones de diseño de software

bornex

Aun que los patrones de diseño son una cuestión más de Desarrollo (en general) que de Diseño, lo pongo en la categoría de Diseño.

Puesto que hay mucho interés en este foro por aprenderlos y son conocidos como el "sexo adolescente" todo el mundo habla de él pero realmente nadie sabe como funciona. Voy a dar un poco de claridad al asunto :P

Yo como muchos, soy un completo novato en esto de los patrones y se lo justo y necesario, he utilizado alguno y he llegado a crear alguna aplicación.

1. Introducción

Parece ser que para ser un buen desarrollador es imprescindible conocer y saber de patrones de diseño, me atrevería a decir que es casi obligatorio saber de ellos. Los patrones de diseño o también conocidos como design patterns se pueden dividir principalmente en tres grandes familias: los patrones de construcción, los patrones de estructuración y los patrones de comportamiento.

Aquí yo os daré una ligera pincelada de los 23 + 1 patrones de diseño más famosos y utilizados, pero existen muchísimos más, y cada día se inventan uno nuevo, "parece ser" que están de moda.

Los patrones se introducen en 1995 con el libro del llamado "GoF", de Gang of Four (en referencia a la "banda de los cuatro" autores), llamado "Design Patterns - Elements of Reusable Object-Oriented Software" escrito por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides. Este libro constituye la obra de referencia acerca de patrones de diseño.

Pero, hasta hace unos pocos años (6 o 7) no han cobrado importancia, de tal manera que son requisito imprescindible para desempeñar un trabajo como desarrollador o participar en proyectos open source.

Pero, realmente ¿qué es un patrón de diseño?

Un design pattern o patrón de diseño consiste en un diagrama de objetos que forma una solución a un problema conocido y frecuente. El diagrama de objetos está constituido por un conjunto de objetos descritos por clases y las relaciones que enlazan los objetos.

Los patrones responden a problemas de diseño de aplicaciones en el marco de la programación orientada a objetos. Se trata de soluciones conocidas y probadas cuyo diseño proviene de la experiencia de los programadores. No existe un aspecto teórico en los patrones, en particular no existe una formalización (a diferencia de los algoritmos).

2. Catálogo de patrones de diseño

Y aquí os dejo la gran lista de patrones de diseño, claramente pondré un ejemplillo de alguno, y los describiré brevemente.

2.1 Patrones de construcción

-Abstract Factory: tiene como objetivo la creación de objetos reagrupados en familias sin tener que conocer las clases concretas destinadas a la creación de estos objetos.

-Builder: permite separar la construcción de objetos complejos de su implementación de modo que un cliente pueda crear estos objetos complejos con implementaciones diferentes.

-Factory Method: tiene como objetivo presentar un método abstracto para la creación de un objeto reportando a las subclases concretas la creación efectiva.

-Prototype: permite crear nuevos objetos por duplicación de objetos existentes llamados prototipos que disponen de la capacidad de clonación.

-Singleton: permite asegurar que de una clase concreta existe una única instancia y proporciona un método único que la devuelve.

2.2 Patrones de estructuración

-Adapter: tiene como objetivo convertir la interfaz de una clase existente en la interfaz esperada por los clientes también existentes para que puedan trabajar de forma conjunta.

-Bridge: tiene como objetivo separar los aspectos conceptuales de una jerarquía de clases de su implementación.

-Composite: proporciona un marco de diseño de una composición de objetos con una profundidad de composición variable, basando el diseño en un árbol.

-Decorator: permite agregar dinámicamente funcionalidades suplementarias a un objeto.

-Facade: tiene como objetivo reagrupar las interfaces de un conjunto de objetos en una interfaz unificada que resulte más fácil de utilizar.

-Flyweight: facilita la compartición de un conjunto importante de objetos con granularidad muy fina.

-Proxy: construye un objeto que se substituye por otro objeto y que controla su acceso.

2.3 Patrones de comportamiento

-Chain of responsibility: crea una cadena de objetos tal que si un objeto de la cadena no puede responder a una petición, la pueda transmitir a sus sucesores hasta que uno de ellos responda.

-Command: tiene como objetivo transformar una consulta en un objeto, facilitando operaciones como la anulación, la actualización de consultas y su seguimiento.

-Interpreter: proporciona un marco para dar una representación mediante objetos de la gramática de un lenguaje con el objetivo de evaluar, interpretándolas, expresiones escritas en este lenguaje.

-Iterator: proporciona un acceso secuencial a una colección de objetos sin que los clientes se preocupen de la implementación de esta colección.

-Mediator: construye un objeto cuya vocación es la gestión y el control de las interacciones en el seno de un conjunto de objetos sin que estos elementos se conozcan mutuamente.

-Memento: salvaguarda y restaura el estado de un objeto.

-Observer: construye una dependencia entre un sujeto y sus observadores de modo que cada modificación del sujeto sea notificada a los observadores para que puedan actualizar su estado.

-State: permite a un objeto adaptar su comportamiento en función de su estado interno.

-Strategy: adapta el comportamiento y los algoritmos de un objeto en función de una necesidad concreta sin por ello cargar las interacciones con los clientes de este objeto.

-Template Method: permite reportar en las subclases ciertas etapas de una de las operaciones de un objeto, estando éstas descritas en las subclases.

-Visitor: construye una operación a realizar en los elementos de un conjunto de objetos. Es posible agregar nuevas operaciones sin modificar las clases de estos objetos.

Por último, y no por ello menos importante

2.4 El patrón composite MVC

Este patrón "va suelto" debido a que es un patrón compuesto y complejo, y hay multitud de variantes del mismo.

Introducción al problema

La realización de la interfaz de usuario de una aplicación resulta un problema complejo. La principal característica del diseño de una interfaz de usuario es que debe ser lo suficientemente flexible para dar respuesta a las siguientes exigencias, propias de una interfaz moderna:

  • Los usuarios de la aplicación pueden solicitar cambios a dicha interfaz para que sea más eficaz o fácil de usar.

  • La aplicación puede ofrecer nuevas funcionalidades, lo cual requiere una actualización de su interfaz de usuario.

  • El sistema de ventanas de la plataforma con el que trabaja la aplicación puede evolucionar e imponer modificaciones en la interfaz de usuario.

  • La misma información puede representarse mediante diferentes vistas e introducirse a través de distintos medios.

  • La representación debe reflejar, inmediatamente, las modificaciones de datos manipulados por la aplicación.

  • Los datos gestionados por la aplicación pueden manipularse simultáneamente a través de varias interfaces: por ejemplo, una interfaz de usuario de escritorio y una interfaz de usuario web.

Estos requisitos hacen casi imposible diseñar una interfaz de usuario que pueda aplicarse en el seno del núcleo funcional de la aplicación. Conviene adoptar, por lo tanto, una solución algo más modular como la que propone el patrón composite MVC.

El patrón MVC

Los autores de Smalltalk-80 proponen una solución a este problema llamada MVC, del acrónimo Model-View-Controller, que preconiza la siguiente separación entre componentes de una aplicación:

  • Model (modelo): se trata del núcleo funcional que gestiona los datos manipulados en la aplicación.

  • View (vista): se trata de los componentes destinados a representar la información al usuario. Cada vista está vinculada con un modelo. Un modelo puede estar vinculado a varias vistas.

  • Controller (controlador): un componente de tipo controlador recibe los eventos que provienen del usuario y los traduce en consultas para el modelo o para la vista. Cada vista está asociada a un controlador.

La estructura genérica, en su forma simplificada, de MVC se representa mediante la notación UML de la figura. El modelo se incluye como el sujeto del patrón Observer y, por lo tanto, como una subclase de la clase abstracta Sujeto. La clase Modelo implementa dos métodos: getDatos y modificaDatos. El primero permite acceder a los datos del modelo y el segundo modificarlos. En la práctica, estos métodos darán un acceso más fino a los datos del modelo, así como a los servicios que implementan las funcionalidades de la aplicación.

La clase Vista se incluye como observador del modelo. El método actualiza se invoca cuando se quiere actualizar los datos del modelo. La vista extrae del modelo los datos que se quieren visualizar y los representa. Además del método actualiza, la vista posee el método manipulaRepresentación destinado al controlador. En efecto, algunas acciones del usuario no tendrán ninguna consecuencia sobre el modelo sino, únicamente, sobre la representación: mover una ventana, alguna acción sobre la barra de desplazamiento, etc.

La clase Vista está asociada con el modelo para que el método actualiza pueda acceder a este último. También está asociada con la clase del controlador. En efecto, es la vista la que crea su controlador y la que conserva una referencia, en particular para poder cambiar de controlador. Cada vista está ligada con un único controlador y cada controlador a una sola vista.

El controlador se incluye, también, como observador del modelo. Esto permite adaptar ciertos componentes gráficos en función de los datos. Por ejemplo, en un navegador, el botón que permite ir a la página siguiente (flecha hacia la derecha) puede permanecer oculto o deshabilitado si no existe dicha página. Esta adaptación se realiza mediante el método actualiza. Éste, igual que su equivalente de la clase Vista, extrae del modelo los datos necesarios.

El método principal del controlador se llama gestionaEvento. Tiene como objetivo gestionar los eventos que provienen del usuario e invocar, a continuación, al método modificaDatos del modelo o bien al método manipulaRepresentación de la vista asociada con el controlador.

Para que los métodos actualiza y gestionaEvento puedan funcionar correctamente, cada controlador está asociado con el modelo y con su vista.

La siguiente tabla resume las responsabilidades de los tres componentes.

3. Frameworks y Templates engines

Para utilizar estos patrones ya existen infinidad de frameworks y motores de plantilla, los cuales son muy útiles para separar la presentación de la capa de aplicación.

Yo personalmente he utilizado FreeMarker para hacer mis applets de Java porque sigue el patrón de diseño MVC y es my práctico. Pero ya digo, que hay miles.

Aquí os dejo un link donde podéis ver los múltiples que hay y su comparación.

Templates engines

11
Wasd

Woah! Gran hilo, aunque me duele verlo en Diseño (porque se sobreentiende que es diseño gráfico). Lo pondría en desarrollo sin dudar.

+1 y a favs, en cuanto pueda aporto algo.

1 respuesta
bornex

#2 Jejeje, lo intente poner en Desarrollo pero no hay una categoría que sea general.

Yo ire aportando gradualmente, cada uno de los patrones que he mencionado en el post, con ejemplos y frameworks. Se puede quedar bastante bien.

Gracias.

1 respuesta
Nucklear

#3 Se podía editar el título por "El hilo de los patrones de diseño de software" o algo así.

Gran hilo, es algo que siempre viene bien recordar y aprender

1 respuesta
bornex

#4 Tienes razón no he caído jajaja. Pero eso tiene que hacerlo un mod. A ver si se pasa uno y lo modifica.

1 respuesta
Nucklear

#5 Puedes avisar a Jastro por MP o por el IRC

eisenfaust

Los patrones de dise;o suelen ser dos cosas:

  1. Correcto uso de las caracteristicas del lenguaje (lo que se entiende como codigo idiomatico).
  2. Parches y workarounds en forma de best practices ante limitaciones de un lenguaje.

Lo de #1 son patrones de dise;o de lenguajes Java-like, no globales, y jamas deberian tratarse como tal.

No tienes por que ser peor desarrollador por no tener ni idea de lo que es por ejemplo un decorator. Y un desarrollador de Java puede pasar toda su carrera sin saber lo que es un functor o un monad, porque no le hace ni falta.

Lo digo para los que tienen el gang of four en la mesita de noche como su biblia personal.

1 3 respuestas
wineMan

Yo descubrí los patrones de diseño cuando se popularizaron hace unos años. Cuando llevas desde los 90 tirando código y lees sobre patrones, te das cuenta de que los has implementado sin conocerlos y has llegado a soluciones iguales o muy similares. Estuve no hace mucho obsesionado con ellos.

Soy pro-patrones de diseño. Pero ojo, se puede caer en el error de intentar aplicarlos sí o sí y perder tiempo en forzar su aplicación ante problemas que no los requieren. El resultado es un código más complejo con patrones que sin patrones.

Cuando los conoces, es mejor olvidarse de ellos. El cerebro ya te avisa cuando estás ante un problema y a la solución óptima le va bien un patrón.

Creo que es de obligado cumplimiento para un programador actual conocerlos. Si no los conoces al dedillo tampoco te sientas un mierda. No pasa nada. No son mantras que haya que memorizar.

#7, sí, tengo mi libro "Código limpio" y links en el iPad de patrones que leo por la noche. ¿Algún problema? xD

Edit:
Mis patrones favoritos: Adapter (sencillo pero muy muy útil y usado), Observer, State y Decorator.

1 respuesta
MTX_Anubis

Yo opino como #7, sobre todo porque la mayoría suelen ser por la segunda causa xD. Añadiría los patrones de arquitectura (que es lo que vendría ser un MVC) que pienso que cumplen una función más global e independiente del lenguaje.

bornex

#7 Hey! noto un cierto resquemor. Puede ser que no sean patrones para todo en general, pero se utilizan bastante en los lenguajes orientados a objetos como por ejemplo Java, C#,...

A lo mejor he pecado por ser poco "purista" pero la verdad que como dice #8 se utilizan bastante y a veces los utilizas desde el total desconocimiento.

Una cosa quiero dejar clara, no he dicho que sea de mal desarrollador pero si te das una vuelta por las ofertas de trabajo piden patrones por todos lados.

Aun así me tomare la molestia de explicar cuando pueda, uno a uno los patrones que he nombrado.

Un saludo.

1 respuesta
B

#10: Los patrones de diseño no dejan de ser mecanismos para suplir carencias del lenguaje. Yo soy el primero en saberlos y aplicarlos pero no caigamos en el error de pensar que todo en la vida es Java o C#. Sí, ya sé que hay muchas ofertas de trabajo sobre esto, pero no solo la cantidad importa.

Un ejemplo claro de lo que digo es el patrón comando: como Java es una mierda y no tiene high-order functions (java 8 tiene un aborto de ello para algunos casos creo) entonces nos creamos una clase para instanciarla y pasarla por ahí que simplemente contiene una operación.

El patrón composite? Tipos algebraicos recursivos.

Strategy? Lo mismo que comando.

Y así podríamos estar toda la vida. Insisto en que para Java/C# me parecen muy útiles y te agradezco que hagas el esfuerzo de mostrárselo a los demás, a algunos PHPeros les vendrá muy bien xD

Este thread acerca del tema es bastante interesante.

2 respuestas
bornex

#11 No estoy diciendo que todo en la vida sea Java o C# obviamente. Cada lenguaje tiene sus usos.

Para high-order function NO usaria Java (Haskell, Python o C serían buena opción entre muchas opciones posibles). En fin, estas intentando pescar con un paraguas. Y sí, soy programador de Java y lo digo, Java está rotísimo (en algunos aspectos).

Insisto yo también, no he dicho en ningún momento que solo sea Java/C#, hay mas cosas en el campo.

zoeshadow

Yo creo que le va a venir muy bien a los desarrolladores de librerías y frameworks para hacer cosas bastante interesantes.

Y contando que una de las razones de peso para usar Java es la cantidad ( y calidad ) de librerías que hay, creo que van a dar mucho juego.

ITT: FP Zealots VS OOP Zealots

Spacelord

Ni diez mensajes hemos tardado en discutir. ¿Tenemos nuevo record?

1 respuesta
MTX_Anubis

#14 Hombre si se habla de patrones de diseño es normal también discutir sobre la utilidad de éstos digo yo xD

Skiuv

Mis favoritos:

Alta cohesión: Nos dice que la información que almacena una clase debe de ser coherente y debe estar (en la medida de lo posible) relacionada con la clase.

Bajo acoplamiento: Es la idea de tener las clases lo menos ligadas entre sí que se pueda. De tal forma que en caso de producirse una modificación en alguna de ellas, se tenga la mínima repercusión posible en el resto de clases, potenciando la reutilización, y disminuyendo la dependencia entre las clases.

2 respuestas
MTX_Anubis

#16 Hombre eso lo veo como conceptos o principios del diseño, no patrones per se.

2 respuestas
wineMan

#16 Como bien dice #17, son principios globales de diseño más que patrones.

Eso sí, son principios que se deberían enseñar desde el minuto 0 en cualquier asignatura de programación/ingeniería de software. Si todos los programadores del mundo mundial hubieran
aplicado estos dos principios desde los 70s, otro gallo hubiera cantado en la mala calidad del software.

P. ej., el mal uso de variables globales ha hecho mucho daño. Enseñan modularidad, POO, etc. pero he visto mil códigos donde en la función más tonta meten dependencias de otras funciones innecesariamente. Y esto sucedió en el tránsito entre la programación procedural y la POO. Hordas de programadores viejunos sin reciclar con un entorno orientado a objetos y tirando código con variables y subrutinas globales...

#11, no denuestes tanto a Java que en Google, tu empresa modelo, lo usan mucho ;)

#19 +1 xD. Son refactorizaciones sanas. Te podría contar algunas historias al respecto. Jefes de 4X años que es mejor que les roben el teclado y se dediquen a otra cosa en vez de a picar código o diseñar sistemas.

3 respuestas
HeXaN

#18 ¿Y la cantidad de gente que se gana el pan "potabilizando" esos códigos? xD

Skiuv

#17 #18 Tenéis razón, pero para mi no solo son patrones de diseño los de arriba (que son más específicos) sino también los GRASP, porque si solo dejas lo de arriba te está faltando una visión mas general y aplicable para un mayor numero de situaciones y de como afrontar los sistemas.

Aunque se debe a mi definición de patrón de diseño, más general y académica. Cuestión de gustos :D :D :D

+1 por el ejemplo xD

1
B

#18: Todo el mundo tiene derecho a tener defectos xD

Usuarios habituales