Logo DIE

Patrones de Diseño

Unidad de Apoyo para el Aprendizaje

Iniciar

Introducción


En ingeniería de software un patrón de diseño es un marco de referencia probado y comprobado, que ha dado buenos resultados en otras implementaciones y por ello se puede seguir de manera general. No es una solución particular, sino una recomendación probada que permite generar código de calidad de forma ágil. Conocer diversos patrones permite tener un amplio panorama de opciones a la hora de proponer una solución de software a la medida.





Implementar una aplicación en un lenguaje orientado a objetos utilizando algún patrón de diseño.

Patrones de software


Un patrón de diseño en ingeniería de software es una solución repetible y general para problemas de ocurrencia cotidianos en el diseño y desarrollo de software. Es importante aclarar que un patrón de diseño no es un diseño terminado y listo para codificarse, sino una descripción o modelo (template) de cómo resolver un problema que puede utilizarse en diferentes situaciones.

Los patrones de diseño permiten agilizar el proceso de desarrollo de solución, debido a que proveen un paradigma desarrollado previamente y que ha sido probado con éxito.

Un diseño de software efectivo debe considerar detalles que tal vez no sean visibles hasta que se implemente la solución, es decir, debe anticiparse a los problemas y tratar de cubrir todos los resquicios. La reutilización de patrones de diseño ayuda a prevenir los detalles sutiles que provocarían problemas más grandes, además de ayudar a la legibilidad de código para programadores o analistas que estén familiarizados con patrones.

De manera general, un patrón de diseño posee cuatro elementos esenciales:

Se utiliza para describir el diseño del problema, su solución y sus consecuencias en una o dos palabras.

Refiere cuándo se debe aplicar el patrón, además de explicar el problema y su contexto. Puede describir tanto problemas de diseño específico, por ejemplo, la representación de algoritmos como objetos, así como estructuras de clases u objetos que son sintomáticos de un diseño inflexible, para evitar caer en ellos. Algunas veces el problema puede incluir una lista de condiciones que se deben cumplir para que el patrón tenga sentido y sea viable en su implementación.

Describe los elementos que forman el diseño, su relación, responsabilidades y colaboraciones. La solución no describe de manera particular un diseño o implementación, más bien provee una descripción abstracta del diseño de un problema y cómo, de manera general, el acomodo de elementos (clases y objetos) resuelve el problema.

Son el resultado y las recompensas de haber aplicado el patrón. Aunque las consecuencias son a menudo poco mencionadas, cuando se describe el diseño de decisiones se vuelven críticas para evaluar el diseño alternativo y poder entender el costo-beneficio de aplicar el patrón. Las consecuencias en la ingeniería de software a menudo se relacionan con compensaciones en espacio y tiempo. Debido a que la reutilización es un factor en el diseño orientado a objetos, las consecuencias de un patrón de diseño incluyen su impacto en la flexibilidad del sistema, su extensibilidad y su portabilidad.

Los puntos de vista afectan la interpretación de qué es y qué no es un patrón. Lo que para una persona puede ser un patrón de diseño para otra puede ser un bloque primitivo de construcción.

El diseño de patrones no establece un diseño como una lista ligada o un hash table que puede ser codificado en clases y reutilizado una y otra vez. Tampoco es tan complejo como para llegar a especificar un diseño en un dominio específico para una aplicación o sistema.

El diseño de patrones es, más bien, una descripción de la comunicación que existe entre objetos y clases, las cuales se pueden personalizar para resolver un problema de diseño general en un contexto en particular.

Se consideran tres tipos de patrones de software:

Diagrama de bloques

Patrones arquitectónicos: describen soluciones al más alto nivel de software y hardware. Normalmente soportan requerimientos no funcionales (criterios de evaluación).

Patrones de diseño: describen soluciones en un nivel medio de estructuras de software. Normalmente soportan requerimientos funcionales (especificaciones técnicas del sistema).

Patrones de programación: describen soluciones en el nivel de software más bajo, a nivel de clases y métodos. Normalmente soportan características específicas de un lenguaje de programación.



Dentro de los patrones de diseño existen tres grandes grupos: los creacionales, los estructurales y los de comportamiento.





Patrón de arquitectura


Un patrón de arquitectura o arquitectónico es una vista estructural de alto nivel que define los estilos o grupos de estilos adecuados para cumplir con requerimientos funcionales y no funcionales. Además, describe la organización fundamental de un sistema incluyendo sus componentes, las relaciones entre ellos, el ambiente, así como los principios que orientan su diseño y evolución.

El patrón arquitectónico, también conocido como arquitectura lógica, consiste en un conjunto de patrones y abstracciones coherentes que proporcionan el marco de referencia necesario para guiar la construcción del software.

Los patrones arquitectónicos son similares al patrón de diseño de software, pero tienen un alcance más amplio. Algunos patrones arquitectónicos conocidos son:

Patrón de capas

Patrón punto a punto

Patrón cliente-servidor

Modelo-vista-controlador

Patrón maestro-esclavo

Patrón de pizarra

Patrón de pipe

Patrón de intérprete

Patrón de intermediario

Patrón de bus de evento



Patrón de diseño arquitectónico MVC

El patrón de diseño modelo-vista-controlador (MVC) asigna objetos con alguno de los tres roles que menciona su nombre. El patrón define los roles que juegan los objetos en la aplicación, así como la manera en la que éstos se comunican entre sí. Dentro de una implementación MVC, la colección de objetos del mismo tipo forma lo que se conoce como capa, por ejemplo, la capa del modelo son todos aquellos objetos que contienen los datos de la solución.

La implementación del patrón MVC provee varios beneficios: los objetos tienden a ser más reutilizados, las interfaces creadas suelen estar mejor definidas y, en general, suelen ser aplicaciones fáciles de extender.

Diagrama de bloques


Modelo MVC

• Modelo

Los objetos que forman parte del modelo encapsulan la información de la aplicación y definen la lógica con la que se van a manipular los datos. Asimismo, un objeto del modelo puede tener relaciones uno a uno o uno a muchos con otros objetos del modelo.

Debido a que los objetos del modelo representan conocimiento y experiencia relacionada con un dominio específico del problema, éstos pueden ser reutilizados en problemas con un dominio similar.

Idealmente, los objetos del modelo no deben tener una conexión explícita con los objetos de la vista, que son los que muestran la información y permiten al usuario modificarla. Las acciones de los usuarios en la capa de vista son comunicadas al modelo a través del Controlador. Así, cuando un objeto del modelo cambia, éste notifica al objeto del controlador para que actualice los objetos de vista necesarios.

• Vista

Un objeto de vista es el objeto de la aplicación que el usuario puede ver y con el cual interactúa. El objeto de vista sabe cómo mostrarse y puede responder a las acciones del usuario. El propósito máximo de un objeto de vista es mostrar la información del objeto del modelo y habilitar la edición de información.

Los objetos de vista se enteran de los cambios en la información a través de los objetos del controlador y la comunicación con el usuario. Asimismo, envían la información recibida del usuario a los objetos del controlador para que éste se los envíe a los objetos del modelo.

• Controlador

Un objeto del controlador actúa como intermediario entre uno o más objetos de la vista y uno o más objetos del modelo. Por lo tanto, los objetos del controlador son un conducto a través del cual los objetos de la vista se enteran de los cambios de los objetos del modelo y viceversa. Los objetos del controlador también pueden establecer y coordinar tareas de la aplicación, así como administrar el ciclo de vida de los objetos.

En general, los objetos del controlador interpretan las acciones realizadas por los usuarios en los objetos de la vista y comunican estas acciones hacia la capa del modelo. Asimismo, cuando un objeto del modelo cambia, el objeto del controlador envía la información a los objetos de la vista para que ésta pueda ser mostrada.

Problema

Se requieren mostrar varias pantallas de manera gráfica (vista) con la información que se encuentra en un repositorio de datos (modelo). Debe existir un mediador (controlador) entre las pantallas y el repositorio de datos para facilitar la comunicación y el paso de información.




Solución

Se debe desacoplar la información (modelo de datos) del código de la interfaz gráfica que construye la vista, de manera que se construyan varias vistas.

Cuando se ejecute la aplicación, se puede registrar cada vista con el modelo de información correspondiente a través de un controlador de paso de información (observador).




Consecuencias

MVC desacopla vistas y modelos estableciendo un protocolo de suscriptor/notificador entre ellos, de tal manera que debe asegurarse que la vista refleje el estado del modelo. Así, si la información del modelo cambia, el modelo debe notificar a la vista que depende de él.

Se pueden acoplar varias vistas a un modelo para mostrar diferente información. También se pueden crear nuevas vistas sin necesidad de reescribir el modelo.

Permite manejar las entradas del usuario sin necesidad de cambiar la presentación (vista), ya que la capacidad de responder ante un estímulo de la vista se encapsula en el controlador, el cual puede implementar diversas respuestas dependiendo del estímulo enviado por la vista, sin modificarla.

Ejemplo

Una aplicación debe mostrar información analítica (información numérica) y gráfica (gráfica de barras) a partir de una base de datos; del mismo modo, puede presentar un reporte de la información mostrada.



Diagrama de bloques

Patrón de diseño creacional


Un patrón de diseño creacional de clases utiliza la herencia para variar la clase que crea una instancia, mientras que un patrón de diseño creacional de objetos delegará la instanciación a otro objeto.

Los patrones creacionales se vuelven importantes como sistemas que evolucionan para depender más de la composición de objetos que de la herencia de clases. A medida que esto sucede, el énfasis se desplaza lejos de un código duro hacia la definición de un conjunto fijo de comportamientos con desempeños fundamentales que pueden ser parte de conjuntos más complejos. Así, la creación de objetos con un comportamiento particular requiere más que simplemente instanciar una clase.

En estos patrones existen dos temas recurrentes:

En el primero se encapsula todo el conocimiento sobre una clase en específico que utiliza el sistema. En el segundo se oculta la manera en la que las instancias de las clases del sistema se crean y se unen entre sí.

Por ende, los patrones creacionales proporcionan mucha flexibilidad en lo que se crea, quién lo crea, cómo lo crea y cuando lo hace. Esto permite configurar un sistema de objetos producto que pueden variar ampliamente en su estructura y funcionalidad.


Diagrama de bloques



Es importante recalcar que algunas veces los patrones relacionales pueden competir entre sí por ser igual de rentables. Algunas otras veces se pueden complementar.

Patrón de diseño creacional Singleton

Problema

En la aplicación debe existir únicamente una instancia de una clase y ésta (la instancia) debe ser accesible para los clientes a través de un punto de acceso bien conocido.

Para algunas aplicaciones es importante tener solamente una instancia en ejecución. Por ejemplo, en un sistema de impresoras se debe tener una sola cola de impresión.




Solución

La clase debe ser la responsable de hacer el seguimiento para una única instancia. La clase puede asegurar que no se pueda crear otra instancia, así como proveer una ruta para acceder a dicho objeto.

Por lo tanto, lo que se debe hacer es una clase que:

      Mantenga su constructor privado.

      Mantenga una instancia como privada y estática.

      Provea un método público y estático para acceder a la instancia.



Diagrama de bloques


Modelo Singleton



Consecuencias



El patrón de diseño creacional Singleton se puede usar cuando:

  • Exista exactamente una instancia de una clase; ésta debe ser accesible desde un punto de acceso bien conocido.

  • Una única instancia deba existir para una subclase y los clientes deban ser capaces de utilizar una subclase sin modificar su código.

Ejemplo

Una impresora dentro de una compañía debe manejar todos los documentos que se envíen para mantener un orden y un registro; ése es un buen lugar para proveer una clase que mantenga una sola instancia de la impresora para todos los objetos que la utilicen. Por lo tanto, se puede usar el patrón Singleton para manejar las impresiones.

Diagrama de bloques

Patrón de diseño estructural


Los patrones de diseño estructural pueden ser de clases o de objetos.

El patrón estructural de clases usa la herencia para componer la implementación de múltiples clases base. Esto quiere decir que, cuando se mezclan varias clases base dentro de una (herencia múltiple), la clase resultante combina las propiedades de todas las clases base, lo que genera una estructura grande. Este patrón es muy útil cuando se quiere hacer que clases desarrolladas de manera independiente y en diferentes bibliotecas trabajen unidas.

El patrón estructural de objetos describe la manera en la que se componen los objetos para reaccionar ante una nueva funcionalidad. Los objetos poseen una composición flexible, esto es, tienen la habilidad de cambiar su forma en tiempo de ejecución, lo cual no es posible con una composición estática.



Patrón de diseño estructural Composite

Nombre: Composite




Problema

Se requiere manejar varios componentes. Todos los componentes tienen las mismas operaciones, pero funcionalidades distintas (algunos más generales, otros más específicas).

La idea principal es que todos los componentes se puedan manejar con una misma referencia.




Solución

Crear una clase abstracta Component que contenga una jerarquía de clases, de tal manera que las referencias a cualquier subclase de Component se puedan manejar desde la clase abstracta.




Consecuencias

Los beneficios de utilizar el patrón de diseño Composite son los siguientes:

Definir una jerarquía de clases que consiste en objetos primitivos y compuestos, donde los objetos primitivos pueden componer objetos más complejos, que a su vez pueden componer objetos más robustos, y así de manera recursiva.

Hacer la tarea del cliente simple, ya que puede tratar con estructuras compuestas u objetos de manera uniforme.

Facilitar la creación de nuevas funcionalidades. Debido a que los cambios se ven reflejados en las clases compuestas, el cliente no se ve obligado a agregar código y puede utilizar las nuevas funcionalidades.

La creación de nuevas funcionalidades de manera sencilla provoca que sea difícil restringir los componentes nuevos, por la misma facilidad para agregar.

Ejemplo

Se desea crear una aplicación gráfica con varios componentes. Éstos pueden ser un botón, una caja de texto o una imagen.

Diagrama de bloques




Patrón de diseño de comportamiento


Los patrones de diseño de comportamiento se caracterizan por un complejo control de flujo, el cual es difícil manejar en tiempo de ejecución, por lo que se provoca que el enfoque se cambie lejos del control de flujo para concentrarse exclusivamente en la manera en la que los objetos se comunican.


Patrón de diseño de comportamiento Observer

Nombre: Observer

Problema

Se necesita notificar a un grupo de diferentes objetos que un evento ha ocurrido en la aplicación.

Un cambio en el estado de un objeto requiere que se cambie el estado de otros objetos sin saber cuántos son los objetos que deben reflejar el cambio.




Solución

Se crea una clase abstracta que será la encargada de manejar un conjunto de objetos observadores en la aplicación.

Cuando un cambio ocurra en el sujeto observado, se debe notificar a todos los objetos observadores dentro del conjunto.



Diagrama de bloques


Modelo Singleton



Consecuencias

El patrón de diseño de comportamiento Observer permite partir un sistema en una colección de clases cooperativas, lo que genera consistencia de información entre los objetos relacionados; además, permite que la clase tenga un bajo acoplamiento y se pueda reutilizar.

Ejemplo

Se desean crear gráficas de una aplicación gráfica que permita separar el aspecto (la presentación) de la información subyacente. Además, se desea que los datos y la presentación de los mismos se puedan reutilizar de manera independiente y trabajar en conjunto.

Diagrama de bloques
ícono

Actividad. Identificación de patrones de diseño

Los patrones de diseño son una guía para crear soluciones de software. Existen diversos patrones de software, acordes a diferentes necesidades. Es muy valioso tener en cuenta los patrones existentes porque pueden ahorrar tiempo al realizar una implementación de software a la medida.

ícono

Autoevaluación. Descripción de patrones de diseño

Para poder utilizar correctamente un patrón de diseño es necesario conocer sus objetivos y características generales. Dichos elementos (objetivos y características) permitirán identificar un patrón de diseño en una aplicación ya desarrollada o elegir el patrón de diseño más adecuado para una nueva implementación.


Fuentes de información

Gamma, E., Helm, R. et ál. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley Professional.


Cómo citar


Solano, J. A. (2020). Patrones de diseño. Unidades de Apoyo para el Aprendizaje. CUAIEED/Facultad de Ingeniería-UNAM. (Vínculo)