Patrón de Diseño Adaptador en Programación

Patrones Estructurales

Los patrones estructurales se enfocan en cómo organizar las clases y objetos de un sistema para crear estructuras más grandes y complejas. El objetivo principal es establecer relaciones entre entidades diferentes, proporcionando combinaciones de objetos que generan nuevas funcionalidades.

El Problema de la Incompatibilidad de Interfaces

En situaciones donde necesitamos integrar un componente legacy con un nuevo sistema, o viceversa, nos encontramos frecuentemente con el problema de que las interfaces no son compatibles. Modificar el código existente puede resultar arriesgado, ya que cualquier cambio puede afectar múltiples partes del sistema y potencialmente causar fallos inesperados.

La solución consiste en crear una capa intermedia que actúe como puente entre ambas interfaces, realizando las conversiones necesarias para que puedan comunicarse sin problemas.

El Patrón Adaptador

El patrón Adaptador (Adapter Pattern) permite convertir la interfaz de una clase en otra interfaz que el cliente espera. Esto posibilita que clases con interfaces incompatibles puedan trabajar juntas de manera transparente.

Participantes del Patrón

  • Target (Objetivo): Define la interfaz específica que el cliente utiliza.
  • Adaptee (Adaptado): La clase existente con funcionalidad necesaria pero interfaz incompatible.
  • Adapter (Adaptador): Implementa la interfaz objetivo y traduce las llamadas al adaptado.

Implementaciones Disponibles

Existen dos enfoques principales para implementar este patrón:

  • Adaptador de clase: Utiliza herencia múltiple para combinar las interfaces.
  • Adaptador de objeto: Utiliza composición, delegando las llamadas al objeto adaptado.

Cuándo Aplicar el Patrón

  • Cuando necesitamos utilizar una clase existente pero su interfaz no corresponde a nuestros requerimientos.
  • Cuando queremos crear clases reutilizables que cooperen con clases que tienen interfaces incompatibles.
  • Cuando necesitamos integrar bibliotecas de terceros o código legacy sin modificar el código fuente original.
  • En adaptadores de objeto, cuando precisamos acceder a funcionalidades de clases derivadas que no podemos modificar directamente.

Comparación de Enfoques

Adaptador de clase:

  • Permite redefinir comportamiento del adaptado parcialmente.
  • No funciona cuando necesitamos adaptar una clase y todos sus descendientes.
  • Comunicación directa sin necesidad de referencias adicionales.

Adaptador de objeto:

  • Un único adapter puede работать con múltiples adaptados y sus subclases.
  • Permite añadir funcionalidades a todos los adaptados conjuntamente.
  • Redefinir comportamiento del adaptado requiere crear subclases y referenciarlas.

Ejemplo Práctico: Sistema de Pagos

class InterfacePago(metaclass=ABCMeta): @abstractmethod def ejecutar_pago(self, monto): """Ejecuta el pago con el monto especificado""" pass

class PasarelaAlipay(InterfacePago): def ejecutar_pago(self, monto): print(f"Procesando con Alipay: {monto} USD")

class PasarelaApple(InterfacePago): def ejecutar_pago(self, monto): print(f"Procesando con Apple Pay: {monto} USD")

Clase existente con interfaz diferente

class SistemaWechat: def procesar_transaccion(self, monto): print(f"Procesando con Wechat: {monto} USD")

Adaptador de clase mediante herencia múltiple

class AdaptadorWechatClase(InterfacePago, SistemaWechat): def ejecutar_pago(self, monto): return self.procesar_transaccion(monto)

Adaptador de objeto mediante composición

class AdaptadorWechatObjeto(InterfacePago): def init(self, sistema): self.sistema_externo = SistemaWechat()

def ejecutar_pago(self, monto):
    return self.sistema_externo.procesar_transaccion(monto)

Pruebas

print("=== Adaptador de clase ===") AdaptadorWechatClase().ejecutar_pago(100)

print("\n=== Adaptador de objeto ===") AdaptadorWechatObjeto(SistemaWechat()).ejecutar_pago(200)


</div>Segundo Ejemplo: Múltiples Sistemas de Pago
-------------------------------------------

<div>```
from abc import ABCMeta, abstractmethod


class ProtocoloPago(metaclass=ABCMeta):
    @abstractmethod
    def liquidar(self, cantidad):
        """Procesa el pago"""
        pass


class ImplementacionWechat(ProtocoloPago):
    def liquidar(self, cantidad):
        print(f"Pago completado vía Wechat: {cantidad} USD")


class ImplementacionTarjeta(ProtocoloPago):
    def liquidar(self, cantidad):
        print(f"Pago completado vía Tarjeta: {cantidad} USD")


class ImplementacionPaypal(ProtocoloPago):
    def liquidar(self, cantidad):
        print(f"Pago completado vía PayPal: {cantidad} USD")


# Adaptador de clase
class AdaptadorUnificado(ProtocoloPago, ImplementacionWechat):
    def liquidar(self, cantidad):
        self.liquidar(cantidad)


cliente = AdaptadorUnificado()
cliente.liquidar(150)


# Adaptador de objeto genérico
class PuentePago(ProtocoloPago):
    def __init__(self, metodo_pago):
        self.metodo = metodo_pago

    def liquidar(self, cantidad):
        self.metodo.liquidar(cantidad)


def probar_sistema(pago):
    pago.liquidar(75)


probar_sistema(PuentePago(ImplementacionTarjeta()))

class ComponenteExterno: def operacion_original(self): print("Ejecutando operación del componente externo")

El adaptador hereda de la interfaz requerida

para mantener compatibilidad con el código cliente

class AdaptadorComponente(InterfazRequerida): def init(self): self.componente = ComponenteExterno()

def operacion_estandar(self):
    self.componente.operacion_original()

if name == "main": objeto = AdaptadorComponente() objeto.operacion_estandar()


</div>Conclusão
---------

El patrón Adaptador es fundamental para lograr la interoperabilidad entre sistemas con interfaces diferentes. Su implementación选用 Depends de los requiistos específicos del proyecto, considerando factors como la flexibilidad necesaria, el acoplamiento deseado y la posibilidad de trabajar con jerarquías de clases

Etiquetas: patrones-de-diseño diseño-estructural Python programación-orientada-a-objetos integración-de-sistemas

Publicado el 7-30 12:10