¿Qué son los Patrones de Comportamiento?
Los patrones de comportamiento son soluciones reutilizables que se enfocan en la interacción y responsabilidad entre objetos. Estos patrones ayudan a definir cómo los objetos se comunican y colaboran entre sí, promoviendo la flexibilidad y la reutilización del código.
Características Clave de los Patrones de Comportamiento
- Interacción entre Objetos: Definen cómo los objetos se comunican y colaboran para realizar tareas complejas.
 - Desacoplamiento: Promueven el desacoplamiento entre los objetos, permitiendo que los cambios en uno no afecten a los demás.
 - Flexibilidad: Facilitan la adición de nuevas funcionalidades sin modificar el código existente.
 - Reutilización: Fomentan la reutilización de código al proporcionar soluciones probadas y optimizadas.
 
Clasificación de los Patrones de Comportamiento
Los patrones de comportamiento se pueden clasificar en dos categorías principales:
- Patrones de Comportamiento de Clase: Se enfocan en la relación entre clases y sus subclases. Utilizan la herencia para distribuir el comportamiento entre las clases.
 - Patrones de Comportamiento de Objeto: Se enfocan en la relación entre objetos. Utilizan la composición de objetos en lugar de la herencia.
 
Ejemplos de Patrones de Comportamiento
A continuación, se presentan algunos de los patrones de comportamiento más comunes:
- Chain of Responsibility: Permite que varios objetos tengan la oportunidad de manejar una solicitud, pasando la solicitud a lo largo de una cadena de manejadores.
 - Command: Encapsula una solicitud como un objeto, permitiendo parametrizar a los clientes con diferentes solicitudes, colas o registros de solicitudes.
 - Interpreter: Define una representación gramatical para un lenguaje y un intérprete que usa la representación para interpretar sentencias en el lenguaje.
 - Iterator: Proporciona una forma de acceder secuencialmente a los elementos de un objeto agregado sin exponer su representación subyacente.
 - Mediator: Define un objeto que encapsula cómo un conjunto de objetos interactúan.
 - Memento: Permite capturar y externalizar el estado interno de un objeto sin violar la encapsulación, para que el objeto pueda ser restaurado a este estado más tarde.
 - Observer: Define una dependencia de uno a muchos entre objetos, de manera que cuando un objeto cambia de estado, todos sus dependientes son notificados y actualizados automáticamente.
 - State: Permite a un objeto alterar su comportamiento cuando su estado interno cambia.
 - Strategy: Define una familia de algoritmos, encapsula cada uno y los hace intercambiables.
 - Template Method: Define el esqueleto de un algoritmo en una operación, diferiendo algunos pasos a las subclases.
 - Visitor: Representa una operación a realizar en los elementos de una estructura de objetos.
 
Ventajas y Desventajas de los Patrones de Comportamiento
Ventajas
- Modularidad: Facilitan la creación de sistemas modulares y mantenibles.
 - Reutilización: Promueven la reutilización de código al proporcionar soluciones probadas.
 - Flexibilidad: Permiten agregar nuevas funcionalidades sin modificar el código existente.
 - Desacoplamiento: Reducen la dependencia entre objetos, lo que facilita el mantenimiento y la evolución del sistema.
 
Desventajas
- Complejidad: Pueden aumentar la complejidad del sistema debido a la introducción de múltiples objetos y relaciones.
 - Sobrecarga de Rendimiento: En algunos casos, la implementación de estos patrones puede introducir una sobrecarga de rendimiento debido a la creación de objetos adicionales y la gestión de la comunicación entre ellos.
 
Ejemplo Práctico: Patrón Observer
Descripción
El patrón Observer define una relación de dependencia uno-a-muchos entre objetos, de manera que cuando un objeto cambia de estado, todos sus dependientes son notificados y actualizados automáticamente.
Implementación en Python
class Subject:
    def __init__(self):
        self._observers = []
    def attach(self, observer):
        self._observers.append(observer)
    def detach(self, observer):
        self._observers.remove(observer)
    def notify(self):
        for observer in self._observers:
            observer.update(self)
class ConcreteSubject(Subject):
    def __init__(self, state):
        super().__init__()
        self._state = state
    @property
    def state(self):
        return self._state
    @state.setter
    def state(self, value):
        self._state = value
        self.notify()
class Observer:
    def update(self, subject):
        pass
class ConcreteObserver(Observer):
    def update(self, subject):
        print(f"Observer: Reacted to the state change to {subject.state}")
# Uso del patrón Observer
subject = ConcreteSubject(0)
observer1 = ConcreteObserver()
observer2 = ConcreteObserver()
subject.attach(observer1)
subject.attach(observer2)
subject.state = 10  # Notifica a los observadoresExplicación del Código
- Subject: Clase base que mantiene una lista de observadores y proporciona métodos para adjuntar, desadjuntar y notificar a los observadores.
 - ConcreteSubject: Extiende la clase 
Subjecty mantiene el estado que se observa. Cuando el estado cambia, notifica a todos los observadores. - Observer: Clase base para los observadores, define el método 
updateque se llama cuando elSubjectcambia de estado. - ConcreteObserver: Implementa el método 
updatepara reaccionar a los cambios en elSubject. 
Ejercicio Práctico
Implementa el patrón Observer para un sistema de notificaciones de temperatura. Crea una clase TemperatureSensor que actúe como el Subject y una clase TemperatureDisplay que actúe como el Observer. El TemperatureSensor debe notificar a todos los TemperatureDisplay cuando la temperatura cambie.
Solución
class TemperatureSensor:
    def __init__(self):
        self._observers = []
        self._temperature = 0
    def attach(self, observer):
        self._observers.append(observer)
    def detach(self, observer):
        self._observers.remove(observer)
    def notify(self):
        for observer in self._observers:
            observer.update(self)
    @property
    def temperature(self):
        return self._temperature
    @temperature.setter
    def temperature(self, value):
        self._temperature = value
        self.notify()
class TemperatureDisplay:
    def update(self, sensor):
        print(f"Temperature Display: The current temperature is {sensor.temperature}°C")
# Uso del patrón Observer
sensor = TemperatureSensor()
display1 = TemperatureDisplay()
display2 = TemperatureDisplay()
sensor.attach(display1)
sensor.attach(display2)
sensor.temperature = 25  # Notifica a los displays
sensor.temperature = 30  # Notifica a los displaysExplicación del Ejercicio
- TemperatureSensor: Actúa como el 
Subject, mantiene una lista de observadores y notifica a los observadores cuando la temperatura cambia. - TemperatureDisplay: Actúa como el 
Observer, actualiza la visualización de la temperatura cuando elTemperatureSensornotifica un cambio. 
Conclusión
En esta sección, hemos introducido los patrones de comportamiento, destacando su importancia en la interacción y responsabilidad entre objetos. Hemos explorado sus características, ventajas y desventajas, y proporcionado un ejemplo práctico del patrón Observer. En las siguientes secciones, profundizaremos en cada uno de los patrones de comportamiento, proporcionando ejemplos detallados y ejercicios prácticos para reforzar el aprendizaje.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
 - Historia y Origen de los Patrones de Diseño
 - Clasificación de los Patrones de Diseño
 - Ventajas y Desventajas de Usar Patrones de Diseño
 
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
 - Singleton
 - Factory Method
 - Abstract Factory
 - Builder
 - Prototype
 
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
 - Chain of Responsibility
 - Command
 - Interpreter
 - Iterator
 - Mediator
 - Memento
 - Observer
 - State
 - Strategy
 - Template Method
 - Visitor
 
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
 - Ejemplos Prácticos de Uso de Patrones
 - Patrones de Diseño en Proyectos Reales
 - Refactorización Usando Patrones de Diseño
 
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
 - Patrones de Diseño en Microservicios
 - Patrones de Diseño en Sistemas Distribuidos
 - Patrones de Diseño en Desarrollo Ágil
 
