¿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

  1. Interacción entre Objetos: Definen cómo los objetos se comunican y colaboran para realizar tareas complejas.
  2. Desacoplamiento: Promueven el desacoplamiento entre los objetos, permitiendo que los cambios en uno no afecten a los demás.
  3. Flexibilidad: Facilitan la adición de nuevas funcionalidades sin modificar el código existente.
  4. 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:

  1. 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.
  2. 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

  1. Subject: Clase base que mantiene una lista de observadores y proporciona métodos para adjuntar, desadjuntar y notificar a los observadores.
  2. ConcreteSubject: Extiende la clase Subject y mantiene el estado que se observa. Cuando el estado cambia, notifica a todos los observadores.
  3. Observer: Clase base para los observadores, define el método update que se llama cuando el Subject cambia de estado.
  4. ConcreteObserver: Implementa el método update para reaccionar a los cambios en el Subject.

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

  1. TemperatureSensor: Actúa como el Subject, mantiene una lista de observadores y notifica a los observadores cuando la temperatura cambia.
  2. TemperatureDisplay: Actúa como el Observer, actualiza la visualización de la temperatura cuando el TemperatureSensor 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.

© Copyright 2024. Todos los derechos reservados