Patrones de Diseño en Programación (PDF)

Summary

Este documento proporciona una descripción de varios patrones de diseño de software, con ejemplos y explicaciones. Se centra en patrones como Observer, Factory Method y Abstract Factory, fundamentales en la programación orientada a objetos, y su aplicación en contextos como la actualización de catálogos en tiempo real.

Full Transcript

**¿Que es un patrón de diseño?** Un patrón de diseño es una forma reutilizable de resolver un problema común, te ahorran tiempo porque no necesitas de buscar siempre una nueva solución a problemas recurrentes, reduciendo eficacia como desarrollador, también te ayudan a estar seguro de la validez de...

**¿Que es un patrón de diseño?** Un patrón de diseño es una forma reutilizable de resolver un problema común, te ahorran tiempo porque no necesitas de buscar siempre una nueva solución a problemas recurrentes, reduciendo eficacia como desarrollador, también te ayudan a estar seguro de la validez de tu código, dado que estos patrones fueron testeados por millones de devs a lo largo de los años, y establecen un lenguaje común, te ayudará a explicar a otras personas, conozcan o no tu código, a entender cómo atajar el problema Un patrón de diseño es una descripción de clases y objetos comunicándose entre sí, adaptado para resolver un problema de diseño general en un contexto particular Cada patrón describe un problema que ocurre una y otra vez en nuestro entorno, describe también el núcleo de la solución al problema, de forma que se pueda usar un millon de veces sin tener que hacer dos veces lo mismo Un patrón es: - - - Pregunta 1: Actualización de Catálogo en Tiempo Real Contexto: Una agencia de autos necesita que el catálogo de vehículos se actualice en tiempo real en todas las visualizaciones cuando la información de un vehículo cambie. Esto requiere un sistema que maneje múltiples visualizaciones y actualice cada una automáticamente al modificarse los datos. Respuestas: 1\. **¿Qué tipo de diseño/patrón aplicar para que los catálogos se puedan visualizar en tiempo real?** El patrón Observer es ideal en este caso, ya que permite que múltiples \"observadores\" (en este caso, las visualizaciones del catálogo) se mantengan sincronizados con el estado del objeto \"observado\" (los datos del catálogo de vehículos). Con el patrón Observer, cada vez que cambian los datos del catálogo, todos los observadores son notificados automáticamente y pueden actualizarse en tiempo real. 2\. **¿Cómo lograr que el diseño soporte el cambio relativo en forma dinámica?** Para lograr dinamismo en el diseño, el patrón Observer permite agregar o eliminar visualizaciones (observadores) sin necesidad de modificar el código de la clase de datos del catálogo (el sujeto observado). Cada observador se suscribe a los cambios y puede optar por desuscribirse, lo que hace que el sistema sea flexible y escalable para futuras modificaciones. 3\) **¿Cómo lograr un diseño flexible que soporte las diferentes modificaciones?** El diseño se hace flexible **utilizando interfaces o clases abstractas tanto para el \"sujeto\" (catálogo de vehículos x ej) como para los \"observadores\" (visualizaciones)**. Esto permite que el sistema soporte diferentes tipos de visualizaciones sin cambiar la lógica principal. Si se desea añadir nuevas formas de visualizar el catálogo, solo es necesario crear nuevas implementaciones del observador. Patrones creacionales Estos patrones proporcionan mecanismos de creación de objetos que incrementan la flexibilidad y la reutilización del código existente. Factory Method, Abstract Factory, Builder, Singleton Patrones estructurales Estos patrones explican cómo ensamblar objetos y clases en estructuras más grandes, mientras se mantiene la flexibilidad y eficiencia de la estructura. Adapter, Facade Patrones de comportamiento Estos patrones tratan con algoritmos y la asignación de responsabilidades entre objetos. Observer, State, Strategy, Memento **Factory Method**: es un patrón de diseño creacional que proporciona una interfaz para crear objetos en una superclase, mientras permite a las subclases alterar el tipo de objetos que se crearán. El Factory Method es un patrón de diseño creacional que define una interfaz para crear objetos, permitiendo que las subclases determinen qué tipo de objeto instanciar. Esto es útil cuando el código necesita crear objetos de diferentes tipos sin depender de sus clases específicas. Resumen **Problema**: Al agregar un nuevo tipo de transporte (como Barco) a una aplicación que solo soportaba Camiones, el código existente tendría que modificarse extensivamente si estuviera acoplado a una clase específica, como Camión. Esto crearía código difícil de mantener y con muchas condiciones. **Solución**: El Factory Method sugiere reemplazar el uso directo de new con un método fábrica. Este método se implementa en una superclase y puede ser sobrescrito en las subclases para producir diferentes tipos de objetos. Así, la lógica de creación de objetos se centraliza en un lugar y el código cliente no necesita conocer la clase específica de cada objeto. **Estructura:** - - - **Ventaja**: El patrón permite añadir fácilmente nuevos tipos de productos sin cambiar el código cliente ni la clase base, promoviendo la extensibilidad y reduciendo el acoplamiento. ![](media/image10.png) **Abstract Factory** es un patrón de diseño creacional que nos permite producir familias de objetos relacionados sin especificar sus clases concretas. El Abstract Factory es un patrón de diseño creacional que permite crear familias de objetos relacionados sin especificar sus clases concretas. Es ideal cuando el sistema debe trabajar con distintos grupos de productos (familias) y es importante que los productos de cada grupo se usen juntos. Resumen **Problema**: Supongamos que desarrollas una interfaz de usuario para distintos sistemas operativos (Windows, macOS, Linux). Cada sistema requiere su propia apariencia y funcionalidad específica en componentes como botones, menús y ventanas. Crear cada componente directamente con new sería complicado, ya que implicaría múltiples cambios cuando se introduce un nuevo sistema operativo. **Solución**: El patrón Abstract Factory sugiere crear una interfaz para una fábrica abstracta que declare métodos para crear cada tipo de objeto (por ejemplo, crearBoton(), crearVentana()). Cada fábrica concreta implementará estos métodos y producirá componentes específicos de una familia (p. ej., FabricaWindows, FabricaMacOS). Así, todos los componentes de una familia son creados juntos y mantienen coherencia. **Estructura**: - - - **Ventaja**: Abstract Factory facilita la creación de familias de productos coherentes y es fácil de extender para admitir nuevas familias sin modificar el código cliente. **Builder** es un patrón de diseño creacional que nos permite construir objetos complejos paso a paso. El patrón nos permite producir distintos tipos y representaciones de un objeto empleando el mismo código de construcción. **Problema:** Crear un objeto complejo, como una casa o un vehículo, puede requerir varios pasos de configuración. Si se usa un constructor convencional, los parámetros se vuelven difíciles de manejar, especialmente si algunos son opcionales o tienen valores por defecto. El código también puede volverse confuso y difícil de entender. **Solución:** Builder sugiere usar una clase Builder para construir el objeto paso a paso. Cada método de la clase Builder configura una parte del objeto, y al final se invoca un método para obtener el objeto completo y configurado. **Estructura:** Builder Abstracto: Define los pasos necesarios para construir el objeto (p. ej., construirParedes(), construirTecho(), construirPuertas()). Builder Concreto: Implementa estos pasos para construir una variante específica del objeto (por ejemplo, una Casa Moderna o un Automóvil Deportivo). Director (Opcional): Controla el proceso de construcción usando un Builder específico. Esto permite construir objetos en un orden predefinido sin que el cliente intervenga en los detalles. Producto: Es el objeto final que se construye y devuelve por el Builder. **Ventajas:** - - - **Ejemplo** Al construir un auto con Builder: Podrías tener métodos como agregarMotor(), agregarAsientos(), agregarGPS(), etc., para personalizar el auto paso a paso. Al final, llamarías a obtenerResultado() o construir() para obtener el auto completamente configurado. Este patrón es común en escenarios donde la creación de un objeto involucra múltiples pasos opcionales y diferentes configuraciones. ![](media/image11.png) **Adapter** es un patrón de diseño estructural que permite la colaboración entre objetos con interfaces incompatibles. El Adapter (Adaptador) es un patrón de diseño estructural que permite que dos interfaces incompatibles trabajen juntas. Su objetivo es convertir la interfaz de una clase en otra interfaz que el cliente espera, permitiendo que clases con interfaces distintas cooperen sin modificar su código. **Problema:** A menudo, una clase que deseas usar en tu aplicación tiene una interfaz incompatible con el código existente. Por ejemplo, imaginemos que tienes un sistema que usa el método procesar() para manejar datos, pero deseas integrar una biblioteca de terceros que sólo tiene un método iniciarProceso() para realizar la misma función. Sin una solución, el código sería incompatible y difícil de usar. **Solución:** El Adapter sugiere crear una clase adaptadora que actúe como intermediaria. Esta clase implementa la interfaz esperada por el cliente (procesar()), y dentro de este método llama al método iniciarProceso() de la biblioteca de terceros, traduciendo las llamadas de una interfaz a otra. **Estructura:** - - - - **Ventajas**: - - - **Ejemplo** Si tienes una aplicación que usa una interfaz de ConexionBaseDatos con un método conectar(), pero deseas usar una biblioteca que tiene un método abrirConexion() en lugar de conectar(), puedes crear un adaptador que implemente ConexionBaseDatos y, en su método conectar(), invoque abrirConexion() de la biblioteca, permitiendo que tu código funcione sin cambios. Este patrón es útil cuando necesitas integrar sistemas de terceros o piezas de código que no puedes modificar para que trabajen juntos con una interfaz común. **Facade** es un patrón de diseño estructural que proporciona una interfaz simplificada a una biblioteca, un framework o cualquier otro grupo complejo de clases. El Facade (Fachada) es un patrón de diseño estructural que proporciona una interfaz simplificada para un conjunto de interfaces en un sistema complejo. Su objetivo es ocultar la complejidad de un sistema, permitiendo al cliente interactuar con un subsistema a través de una interfaz más simple y fácil de usar. **Problema**: Cuando un sistema es complejo o tiene muchas clases interdependientes (por ejemplo, una biblioteca de gráficos o un sistema de gestión de bases de datos), puede ser complicado de entender y usar. Es probable que el usuario no necesite interactuar con cada componente del sistema, sino solo con una funcionalidad específica. Sin una interfaz simplificada, los usuarios tendrían que conocer detalles innecesarios sobre cómo funcionan los componentes internos. **Solución**: El Facade sugiere crear una clase de fachada que actúe como una interfaz de alto nivel para un grupo de clases o subsistemas. La fachada organiza y centraliza las interacciones necesarias para realizar tareas comunes, llamando a las clases y métodos internos en el orden adecuado para cumplir con la solicitud del cliente. **Estructura**: - - - **Ventajas**: - - - **Ejemplo** Supón que tienes un sistema para reservar vuelos que incluye subsistemas para gestionar boletos, facturación, reservas de asientos y notificaciones. En lugar de que el cliente interactúe directamente con cada subsistema, puedes crear una clase FachadaReservas que tenga un método reservarVuelo(). Este método realiza internamente las llamadas necesarias a los subsistemas para gestionar todos los pasos de la reserva de un vuelo, brindando una interfaz simplificada al cliente. El patrón Facade es muy útil para sistemas grandes y complejos, ya que reduce la carga cognitiva del usuario y centraliza las interacciones en un solo punto de entrada. ![](media/image9.png) **Observer** es un patrón de diseño de comportamiento que te permite definir un mecanismo de suscripción para notificar a varios objetos sobre cualquier evento que le suceda al objeto que están observando. El patrón Observer permite establecer una dependencia de uno a muchos entre objetos, de forma que cuando el estado de un objeto (el sujeto) cambia, se notifica y actualizan automáticamente todos los objetos que dependen de él (los observadores). El patrón Observer es un patrón de diseño de comportamiento que permite que un objeto (\"sujeto\" o \"publisher\") notifique automáticamente a otros objetos (\"observadores\" o \"subscribers\") sobre cualquier cambio en su estado, sin que estos estén acoplados de manera directa. **Es ideal para casos en los que un cambio en un objeto requiere actualizaciones en otros objetos.** **Principios del Patrón Observer** - - - **Estructura del Patrón Observer** - - - - **Ventajas del Patrón Observer** - - - **Ejemplos Comunes de Aplicación** - - - En resumen, el patrón Observer es ideal cuando un cambio en un objeto necesita reflejarse en muchos otros sin acoplar los objetos entre sí. El patrón **State** es un patrón de diseño de comportamiento que permite que un objeto cambie su comportamiento cuando cambia su estado interno. A diferencia de los enfoques tradicionales basados en condiciones (como múltiples estructuras if-else o switch), **el patrón State organiza el comportamiento en distintas clases de estado**, haciendo que el objeto delegue el trabajo a la clase correspondiente según su estado actual. El patrón State permite cambiar el comportamiento de un objeto cuando cambia su estado interno. **Se definen distintos estados concretos e implementan un comportamiento asociado a dicho estado.** **Principios del Patrón State** - - - **Estructura del Patrón State** - - Define los métodos que deben implementarse en cada clase de estado específico. - **Ventajas del Patrón State** - - - **Ejemplos Comunes de Aplicación** - - - En resumen, el patrón State ayuda a que los objetos cambien su comportamiento en tiempo de ejecución al delegar ese comportamiento a clases de estado específicas, permitiendo una arquitectura flexible y fácil de mantener. ![](media/image3.png) **Strategy** es un patrón de diseño de comportamiento que te permite definir una familia de algoritmos, colocar cada uno de ellos en una clase separada y hacer sus objetos intercambiables. El patrón **Strategy** es un patrón de diseño de comportamiento que permite **definir una familia de algoritmos, encapsular cada uno de ellos y hacerlos intercambiables en tiempo de ejecución**. Este patrón se usa cuando tienes diferentes maneras de realizar una tarea específica y quieres que el cliente (o el contexto) pueda seleccionar el método adecuado de forma dinámica sin depender de múltiples condicionales. **Principios del Patrón Strategy** - - - **Estructura del Patrón Strategy** **Contexto**: La clase principal que utiliza diferentes estrategias. Mantiene una referencia a un objeto de la interfaz de estrategia y ejecuta los métodos de la estrategia actual. **Estrategia (interfaz o clase abstracta):** Define una interfaz común que todas las estrategias deben implementar. Esto asegura que el contexto puede usar cualquier estrategia sin conocer su implementación específica. **Estrategias Concretas:** Implementan la interfaz de estrategia con un comportamiento específico. Cada clase de estrategia representa una variante de un algoritmo que puede ser intercambiada en el contexto. **Ventajas del Patrón Strategy** - - - **Ejemplos Comunes de Aplicación** - - - En resumen, el patrón Strategy es ideal cuando tienes múltiples algoritmos que realizan una misma tarea pero de diferentes maneras, y necesitas cambiar entre ellos de forma dinámica y sencilla. **Memento** es un patrón de diseño de comportamiento que te permite guardar y restaurar el estado previo de un objeto sin revelar los detalles de su implementación. El patrón **Memento** es un patrón de diseño de comportamiento que permite capturar y almacenar el estado interno de un objeto, de manera que pueda restaurarse más adelante sin violar el principio de encapsulación. Esto es especialmente útil para implementar funciones de \"deshacer\" o \"rehacer\", ya que permite revertir los cambios a un estado anterior sin exponer los detalles internos del objeto. **Principios del Patrón Memento** - - - **Estructura del Patrón Memento** **Originador:** Es la clase cuyo estado se quiere almacenar y restaurar. Crea y restaura objetos Memento que contienen el estado en un momento específico. **Memento:** Almacena el estado interno del Originador en un momento determinado. No permite modificar su estado una vez creado, y no expone su contenido directamente. **Caretaker:** Administra los objetos Memento y decide cuándo debe crearse y restaurarse un estado. No manipula ni expone el contenido del Memento; simplemente lo guarda y lo utiliza para restaurar el estado del Originador. **Explicación** - - - **Ventajas del Patrón Memento** - - - **Ejemplos Comunes de Aplicación** - - - En resumen, el patrón Memento es excelente cuando necesitas capturar y restaurar el estado de un objeto de manera segura y sin exponer sus detalles internos. ![](media/image5.png) ![](media/image12.png)

Use Quizgecko on...
Browser
Browser