Patrón Puente en Python
El patrón Puente es un patrón de diseño estructural que separa la parte abstracta de la parte de implementación, permitiendo que ambas cambien de forma independiente. En pocas palabras, esseparar las múltiples dimensiones de variación de una cosa para que cada dimensión pueda extenderse de forma independiente.。
Analogía del patrón Puente en la vida cotidiana
Imagina la relación entre un control remoto y un televisor:
- Control remoto(parte abstracta): proporciona la interfaz de control (encendido, volumen, canal)
- Televisor(parte de implementación): ejecuta las operaciones concretas (TV Sony, TV Samsung, TV Xiaomi)
El control remoto no necesita saber cuál es el televisor concreto, ni el televisor necesita saber cuál es el control remoto; se conectan a través de un "puente" y cada uno puede actualizarse y renovarse de forma independiente.
¿Por qué se necesita el patrón Puente?
Limitaciones del enfoque tradicional
Supongamos que queremos diseñar un sistema de dibujo de formas que admita diferentes formas y colores:
Ejemplo
class RedCircle:
def draw(self):
print("Dibujar círculo de color rojo")
class BlueCircle:
def draw(self):
print("Dibujar círculo de color azul")
class RedRectangle:
def draw(self):
print("Dibujar rectángulo de color rojo")
class BlueRectangle:
def draw(self):
print("Dibujar rectángulo de color azul")
# Cada vez que se añade un color o una forma, es necesario crear una nueva clase
# ¡3 colores × 3 formas = 9 clases!
Ventajas del patrón Puente
Ejemplo
class Color:
"""Interfaz de color - parte de implementación"""
def apply_color(self):
pass
class Shape:
"""Abstracción de forma - parte abstracta"""
def __init__(self, color):
self.color = color # ¡La clave del puente!
def draw(self):
pass
# Solo se necesitan: 3 colores + 3 formas = 6 clases
# En lugar de: 3 × 3 = 9 clases
Estructura central del patrón Puente
Entendamos los componentes del patrón Puente con un ejemplo completo:

Cuatro roles clave
- Parte abstracta (Abstraction): define la interfaz abstracta y mantiene una referencia a la parte de implementación
- Abstracción refinada (RefinedAbstraction): extiende la interfaz abstracta
- Parte de implementación (Implementor): define la interfaz de implementación
- Implementación concreta (ConcreteImplementor): implementa concretamente la interfaz
Ejemplo de código completo: sistema de dibujo de formas
Paso 1: Definir la interfaz de la parte de implementación (color)
Ejemplo
class Color(ABC):
"""Interfaz de color - parte de implementación"""
@abstractmethod
def apply_color(self):
pass
class Red(Color):
"""Implementación concreta - rojo"""
def apply_color(self):
return "rojo"
class Blue(Color):
"""Implementación concreta - azul"""
def apply_color(self):
return "azul"
class Green(Color):
"""Implementación concreta - verde"""
def apply_color(self):
return "verde"
Paso 2: Definir la parte abstracta (forma)
Ejemplo
"""Abstracción de forma - parte abstracta"""
def __init__(self, color: Color):
self.color = color # Clave del puente: mantener una referencia a la parte de implementación
@abstractmethod
def draw(self):
pass
class Circle(Shape):
"""Abstracción concreta - círculo"""
def draw(self):
color_name = self.color.apply_color()
print(f"Dibujar círculo de color {color_name}")
class Rectangle(Shape):
"""Abstracción concreta - rectángulo"""
def draw(self):
color_name = self.color.apply_color()
print(f"Dibujar rectángulo de color {color_name}")
class Triangle(Shape):
"""Abstracción concreta - triángulo"""
def draw(self):
color_name = self.color.apply_color()
print(f"Dibujar triángulo de color {color_name}")
Paso 3: Usar el patrón Puente
Ejemplo
def main():
# Crear implementaciones de color
red = Red()
blue = Blue()
green = Green()
# Crear la abstracción de forma y vincular la implementación de color
red_circle = Circle(red)
blue_rectangle = Rectangle(blue)
green_triangle = Triangle(green)
# Dibujar formas
print("=== Resultado del dibujo de formas ===")
red_circle.draw() # Salida: Dibujar círculo de color rojo
blue_rectangle.draw() # Salida: Dibujar rectángulo de color azul
green_triangle.draw() # Salida: Dibujar triángulo de color verde
# Combinación flexible: rectángulo rojo
red_rectangle = Rectangle(red)
red_rectangle.draw() # Salida: Dibujar rectángulo de color rojo
if __name__ == "__main__":
main()
Escenarios de aplicación reales
Escenario 1: Sistema de envío de mensajes
Ejemplo
# Parte de implementación: método de envío de mensajes
class MessageSender(ABC):
@abstractmethod
def send(self, message):
pass
class EmailSender(MessageSender):
def send(self, message):
return f"Enviar por correo electrónico: {message}"
class SMSSender(MessageSender):
def send(self, message):
return f"Enviar por SMS: {message}"
class WeChatSender(MessageSender):
def send(self, message):
return f"Enviar por WeChat: {message}"
# Parte abstracta: tipo de mensaje
class Message(ABC):
def __init__(self, sender: MessageSender):
self.sender = sender
@abstractmethod
def send(self):
pass
class UrgentMessage(Message):
def send(self):
message = "[Urgente] " + self.get_content()
return self.sender.send(message)
def get_content(self):
return "¡El sistema presenta una anomalía, atiéndalo de inmediato!"
class NormalMessage(Message):
def __init__(self, sender: MessageSender, content):
super().__init__(sender)
self.content = content
def send(self):
return self.sender.send(self.content)
# Ejemplo de uso
def message_example():
email_sender = EmailSender()
sms_sender = SMSSender()
# Mensaje urgente enviado por SMS
urgent_sms = UrgentMessage(sms_sender)
print(urgent_sms.send()) # Enviado por SMS: [Urgente] ¡El sistema presenta una anomalía, atiéndalo de inmediato!
# Mensaje normal enviado por correo electrónico
normal_email = NormalMessage(email_sender, "El informe mensual ha sido generado")
print(normal_email.send()) # Enviado por correo electrónico: El informe mensual ha sido generado
message_example()
Escenario 2: Sistema de control remoto de dispositivos
Ejemplo
class Device(ABC):
@abstractmethod
def turn_on(self):
pass
@abstractmethod
def turn_off(self):
pass
@abstractmethod
def set_volume(self, volume):
pass
class TV(Device):
def turn_on(self):
return "Televisor encendido"
def turn_off(self):
return "Televisor apagado"
def set_volume(self, volume):
return f"Volumen del televisor establecido en: {volume}"
class Radio(Device):
def turn_on(self):
return "Radio encendida"
def turn_off(self):
return "Radio apagada"
def set_volume(self, volume):
return f"Volumen de la radio establecido en: {volume}"
# Parte abstracta: control remoto
class RemoteControl:
def __init__(self, device: Device):
self.device = device
def toggle_power(self):
return "Cambiar estado de encendido"
def volume_up(self):
return "Aumentar volumen"
def volume_down(self):
return "Reducir volumen"
class AdvancedRemoteControl(RemoteControl):
def mute(self):
return "Modo silencio"
def set_channel(self, channel):
return f"Cambiar al canal: {channel}"
# Ejemplo de uso
def remote_example():
tv = TV()
radio = Radio()
basic_remote = RemoteControl(tv)
advanced_remote = AdvancedRemoteControl(radio)
print(basic_remote.toggle_power()) # Cambiar estado de encendido
print(advanced_remote.mute()) # Modo silencio
remote_example()
Comparación de ventajas del patrón Puente
| Característica | Enfoque tradicional | Patrón Puente |
|---|---|---|
| Escalabilidad | Mala, requiere modificar el código existente | Buena, se puede extender de forma independiente |
| Número de clases | Muchas, propenso a la explosión de clases | Pocas, crecimiento lineal |
| Mantenibilidad | Difícil, un cambio afecta a todo | Fácil, separación de responsabilidades |
| Flexibilidad | Combinación fija | Combinación dinámica en tiempo de ejecución |
Mejores prácticas y consideraciones
Cuándo usar
✅ Casos adecuados para usar el patrón Puente:
- Cuando se necesita una extensión independiente en múltiples dimensiones
- Cuando se necesita cambiar la implementación en tiempo de ejecución
- Cuando se necesita evitar la vinculación permanente entre la abstracción y la implementación
- Cuando la herencia provocaría una jerarquía de clases demasiado compleja
❌ Casos no adecuados:
- Cuando hay pocas dimensiones de variación y no se necesita un diseño complejo
- Cuando existe un fuerte acoplamiento entre la abstracción y la implementación
Errores comunes y cómo evitarlos
Ejemplo
class BadShape:
def __init__(self, color_type):
if color_type == "red":
self.color = Red()
elif color_type == "blue":
self.color = Blue()
# Aún se debe modificar esta clase para añadir un nuevo color
# Forma correcta: inyección de dependencias
class GoodShape:
def __init__(self, color: Color): # Depender de la interfaz, no de la implementación concreta
self.color = color
Ejercicios
Ejercicio 1: Extender el sistema de formas
Añade las siguientes funcionalidades al sistema de formas:
- Añadir un nuevo color (amarillo)
- Añadir una nueva forma (elipse)
- Crear una elipse amarilla y dibujarla
Ejercicio 2: Diseñar un sistema de pagos
Diseña un sistema de pagos con los siguientes requisitos:
- Métodos de pago: Alipay, WeChat Pay, tarjeta bancaria
- Tipos de pago: pago normal, pago a plazos, pago combinado
- Implementado con el patrón puente para garantizar que los métodos de pago y los tipos de pago puedan extenderse de forma independiente
Resumen
El patrón puente, a través dela separación de la abstracción y la implementación, ofrece una gran flexibilidad. Su idea central es:
- Identificar las dimensiones de cambio: encontrar las múltiples dimensiones del sistema que pueden cambiar de forma independiente
- Establecer un puente: conectar diferentes dimensiones mediante relaciones de composición
- Extensión independiente: cada dimensión puede desarrollarse y cambiar de forma independiente