¿Qué son los Patrones Estructurales?

Los patrones estructurales se centran en la composición de clases y objetos. Su objetivo principal es facilitar el diseño de estructuras complejas mediante la identificación de relaciones simples entre entidades. Estos patrones ayudan a garantizar que, al combinar objetos y clases, el sistema sea flexible y eficiente.

Características Clave de los Patrones Estructurales:

  • Composición de Objetos: Facilitan la creación de estructuras complejas a partir de objetos más simples.
  • Flexibilidad: Permiten que las estructuras sean fácilmente modificables y extensibles.
  • Reutilización: Promueven la reutilización de componentes a través de la composición en lugar de la herencia.

Tipos de Patrones Estructurales

A continuación, se presentan los principales patrones estructurales que se estudiarán en este módulo:

  1. Adapter (Adaptador): Permite que clases con interfaces incompatibles trabajen juntas.
  2. Bridge (Puente): Desacopla una abstracción de su implementación, permitiendo que ambas evolucionen independientemente.
  3. Composite (Composición): Permite tratar objetos individuales y composiciones de objetos de manera uniforme.
  4. Decorator (Decorador): Añade responsabilidades adicionales a un objeto de manera dinámica.
  5. Facade (Fachada): Proporciona una interfaz simplificada a un conjunto de interfaces en un subsistema.
  6. Flyweight (Peso Ligero): Reduce el uso de memoria compartiendo tanto como sea posible con objetos similares.
  7. Proxy (Proxy): Proporciona un sustituto o marcador de posición para otro objeto para controlar el acceso a él.

Ventajas de los Patrones Estructurales

  • Modularidad: Facilitan la creación de sistemas modulares donde los componentes pueden ser desarrollados y probados de manera independiente.
  • Mantenibilidad: Simplifican la estructura del código, lo que facilita su mantenimiento y comprensión.
  • Flexibilidad: Permiten que las estructuras de objetos sean más flexibles y adaptables a cambios futuros.

Desventajas de los Patrones Estructurales

  • Complejidad: En algunos casos, pueden añadir complejidad adicional al sistema debido a la introducción de nuevas clases y objetos.
  • Sobrecarga: Pueden introducir una sobrecarga en términos de rendimiento y memoria, especialmente si no se utilizan correctamente.

Ejemplo Práctico: Uso del Patrón Adapter

Problema:

Supongamos que tenemos una clase Cliente que espera recibir datos de un servicio en un formato específico, pero el servicio actual proporciona los datos en un formato diferente.

Solución:

Utilizaremos el patrón Adapter para crear una clase adaptadora que convierta los datos del formato del servicio al formato esperado por la clase Cliente.

Código de Ejemplo:

# Clase que proporciona datos en un formato específico
class ServicioExistente:
    def obtener_datos(self):
        return {"nombre": "Juan", "edad": 30}

# Clase Cliente que espera los datos en un formato diferente
class Cliente:
    def __init__(self, datos):
        self.nombre = datos["nombre_completo"]
        self.edad = datos["años"]

    def mostrar_datos(self):
        print(f"Nombre: {self.nombre}, Edad: {self.edad}")

# Adaptador que convierte los datos del formato del servicio al formato esperado por el Cliente
class AdaptadorServicio:
    def __init__(self, servicio):
        self.servicio = servicio

    def obtener_datos(self):
        datos = self.servicio.obtener_datos()
        return {
            "nombre_completo": datos["nombre"],
            "años": datos["edad"]
        }

# Uso del adaptador
servicio = ServicioExistente()
adaptador = AdaptadorServicio(servicio)
datos_adaptados = adaptador.obtener_datos()

cliente = Cliente(datos_adaptados)
cliente.mostrar_datos()

Explicación del Código:

  1. ServicioExistente: Proporciona datos en un formato específico.
  2. Cliente: Espera recibir datos en un formato diferente.
  3. AdaptadorServicio: Actúa como un adaptador que convierte los datos del formato del servicio al formato esperado por el cliente.
  4. Uso del Adaptador: Creamos una instancia del servicio existente, la pasamos al adaptador y luego usamos los datos adaptados para crear una instancia del cliente.

Ejercicio Práctico

Ejercicio:

Crea un adaptador para una clase ServicioNuevo que proporciona datos en el siguiente formato:

{
    "first_name": "Juan",
    "years_old": 30
}

El adaptador debe convertir estos datos al formato esperado por la clase Cliente.

Solución:

# Clase que proporciona datos en un formato diferente
class ServicioNuevo:
    def obtener_datos(self):
        return {"first_name": "Juan", "years_old": 30}

# Adaptador que convierte los datos del formato del nuevo servicio al formato esperado por el Cliente
class AdaptadorNuevoServicio:
    def __init__(self, servicio):
        self.servicio = servicio

    def obtener_datos(self):
        datos = self.servicio.obtener_datos()
        return {
            "nombre_completo": datos["first_name"],
            "años": datos["years_old"]
        }

# Uso del adaptador
nuevo_servicio = ServicioNuevo()
adaptador_nuevo = AdaptadorNuevoServicio(nuevo_servicio)
datos_adaptados_nuevos = adaptador_nuevo.obtener_datos()

cliente_nuevo = Cliente(datos_adaptados_nuevos)
cliente_nuevo.mostrar_datos()

Explicación de la Solución:

  1. ServicioNuevo: Proporciona datos en un nuevo formato.
  2. AdaptadorNuevoServicio: Convierte los datos del nuevo formato al formato esperado por el cliente.
  3. Uso del Adaptador: Creamos una instancia del nuevo servicio, la pasamos al adaptador y luego usamos los datos adaptados para crear una instancia del cliente.

Conclusión

En esta sección, hemos introducido los patrones estructurales, destacando su importancia en la composición de clases y objetos para crear estructuras complejas y flexibles. Hemos explorado las ventajas y desventajas de estos patrones y proporcionado un ejemplo práctico del patrón Adapter. En las próximas lecciones, profundizaremos en cada uno de los patrones estructurales mencionados, proporcionando ejemplos detallados y ejercicios prácticos para reforzar el aprendizaje.

© Copyright 2024. Todos los derechos reservados