¿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 observadores
Explicació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
Subject
y 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
update
que se llama cuando elSubject
cambia de estado. - ConcreteObserver: Implementa el método
update
para 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 displays
Explicació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 elTemperatureSensor
notifica 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