El patrón Bridge tiene como objetivo desacoplar una abstracción de su implementación, de manera que ambas puedan variar de forma independiente.
Lo vuelve más flexible, cambia la herencia por composición.
El problema de tener una estructura rígida, donde la abstracción y su implementación están muy acopladas, lo que limita la flexibilidad y la capacidad de extensión porque cualquier cambio en la implementación puede requerir cambiar la abstracción, y viceversa.
La solución que propone el Bridge es:

Este patrón es recomendable cuando:
Principio de separación de intereses: Separa los aspectos de alto nivel (abstracciones) de los detalles de bajo nivel (implementaciones). La implementación puede configurarse en tiempo de ejecución. Cambiar una clase ya no requiere recompilar la abstracción y sus clientes.
Mejora la extensibilidad: Las jerarquías de abstracción e implementador se pueden extender de manera independiente.
Oculta detalles de implementación a los clientes: Podemos aislar a los clientes de los detalles de implementación.
Complejidad Aumentada: Introduce una capa adicional de abstracción, lo que puede complicar el diseño y entender el código.
Costo de Performance: La adición de una capa de abstracción puede resultar en una pequeña penalización en el rendimiento, sobre todo en sistemas muy críticos.
Estamos desarrollando un software avanzado de dibujo, que debe ofrecer flexibilidad en la forma en que se dibujan distintas figuras geométricas.
El desafío es que cada figura geométrica (como círculos, rectángulos, etc.) puede ser representada de múltiples maneras, por ejemplo, renderizada en una pantalla o impresa en papel.
Además, es probable que en el futuro se agreguen más formas y métodos de representación.
Por un lado tenemos formas geométricas y por otro lado métodos de dibujo o representación.
Si codificamos cada combinación de forma geométrica y método de dibujo en las clases de las formas geométricas, vamos a tener un código rígido y difícil de mantener. Agregar un nuevo método de dibujo requeriría modificar todas las clases de las formas geométricas.
Esto va en contra de los principios de diseño de software como la modularidad y la escalabilidad.
Para solucionarlo vamos a usar un Bridge. Este patrón nos permite separar la abstracción (las formas geométricas en sí) de su implementación (cómo se dibujan estas formas). Al hacerlo esto podremos variar y extender tanto las formas como sus métodos de dibujo de manera independiente.
La Abstracción, las Formas Geométricas, son las representaciones de alto nivel de las formas que queremos dibujar, como círculos o rectángulos.
La Implementación, los Métodos de Dibujo, son los distintos modos en que se pueden representar las formas, como en pantalla o en papel.
Definimos una interfaz para los métodos de dibujo (DrawAPI) y creamos dos implementaciones concretas para diferentes entornos (en pantalla y en papel).
Creamos una clase abstracta para las formas geométricas (Shape) y generamos dos implementaciones concretas para formas específicas (Circle y Rectangle), las cuales usan un objeto DrawAPI para realizar el dibujo.
En el cliente (Client), instanciamos nuestras formas concretas indicando la implementación deseada para el método de dibujo.

Codificamos en Java lo que preparamos en el diagrama.
Definimos la Interfaz de Implementación (Métodos de Dibujo):
   // Define la interfaz de implementación para los métodos de dibujo
   interface DrawAPI {
         void drawCircle(double x, double y, double radius);
         void drawRectangle(double x, double y, double width, double height);
   }Implementamos las clases de implementación concretas:
   // Implementación concreta para dibujar en pantalla
   class DrawOnScreen implements DrawAPI {
         public void drawCircle(double x, double y, double radius) {
            System.out.println("Dibujo círculo en pantalla con radio:" + radius);
         }
   
         public void drawRectangle(double x, double y, double width, double height) {
            System.out.println("Dibujo rectángulo en pantalla:" + width + " y " + height);
         }
   }
   
   // Implementación concreta para dibujar en papel
   class DrawOnPaper implements DrawAPI {
         public void drawCircle(double x, double y, double radius) {
            System.out.println("Dibujo círculo en papel en con radio:" + radius);
         }
   
         public void drawRectangle(double x, double y, double width, double height) {
            System.out.println("Dibujo rectángulo en papel:" + width + " y " + height);
         }
   }
            Creamos la abstracción que representa las figuras geométricas:
   // Abstracción de la forma geométrica
   abstract class Shape {
      protected DrawAPI drawAPI;
   
      protected Shape(DrawAPI drawAPI) {
            this.drawAPI = drawAPI;
      }
   
      public abstract void draw();
   }
            Implementamos abstracciones refinadas, cada forma geométrica concreta:
// Implementación concreta de la forma Círculo
   class Circle extends Shape {
      private double x, y, radius;
   
      public Circle(double x, double y, double radius, DrawAPI drawAPI) {
            super(drawAPI);
            this.x = x;
            this.y = y;
            this.radius = radius;
      }
   
      public void draw() {
            drawAPI.drawCircle(x, y, radius);
      }
   }
   
   // Implementación concreta de la forma Rectángulo
   class Rectangle extends Shape {
      private double x, y, width, height;
   
      public Rectangle(double x, double y, double width, double height, DrawAPI drawAPI) {
            super(drawAPI);
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
      }
   
      public void draw() {
            drawAPI.drawRectangle(x, y, width, height);
      }
   }El cliente usa las abstracciones y las Implementaciones, las formas geómetricas y los métodos de dibujo:
   public class Client {
      public static void main(String[] args) {
            Shape circle = new Circle(100, 100, 10, new DrawOnScreen());
            circle.draw();
   
            Shape rectangle = new Rectangle(200, 200, 50, 30, new DrawOnPaper());
            rectangle.draw();
      }
   }Los participantes que vimos antes son: Implementor, ConcreteImplementor, Abstraction, RefinedAbstraction, Client:
Vimos un ejemplo del patrón Bridge, nuestro software de dibujo se vuelve más flexible y fácil de mantener, ya que podemos extender nuestra gama de formas y métodos de dibujo de manera independiente, algo fundamental para un sistema que espera crecer a lo largo del tiempo.
Puede crear y configurar un bridge.
Cambia la interfaz de una clase existente, mientras que Bridge separa la interfaz de la implementación.