Mi granito de java: Bridge

jueves, 2 de junio de 2011

Bridge

Desacopla una abstracción de su implementación, de manera que ambas puedan variar de forma independiente. ¿Que quiere decir exactamente esto? Una abstracción se refiere a un comportamiento que una clase debería implementar, ya sea porque esta obligada por una interface o una clase abstracta. Por otro lado, con implementación se refiere a colocarle lógica a dicha obligación.
Con lo cual, este patrón permite modificar las implementaciones de una abstracción en tiempo de ejecución. Básicamente es una técnica usada en programación para desacoplar la interface de una clase de su implementación, de manera que ambas puedan ser modificadas independientemente sin necesidad de alterar por ello la otra.

Cuando un objeto tiene unas implementaciones posibles, la manera habitual de implementación es el uso de herencias. Muchas veces la herencia se puede tornar inmanejable y, por otro lado, acopla el código cliente con una implementación concreta. Este patrón busca eliminar la inconveniencia de esta solución.

Este patrón debe ser utilizado cuando:
  • Se desea evitar un enlace permanente entre la abstracción y su implementación. Esto puede ser debido a que la implementación debe ser seleccionada o cambiada en tiempo de ejecución.
  • Tanto las abstracciones como sus implementaciones deben ser extensibles por medio de subclases. En este caso, el patrón Bridge permite combinar abstracciones e implementaciones diferentes y extenderlas independientemente.
  • Cambios en la implementación de una abstracción no deben impactar en los clientes, es decir, su código no debe tener que ser recompilado.
  • Se desea compartir una implementación entre múltiples y este hecho debe ser escondido a los clientes.
  • Permite simplificar jerarquías demasiado pobladas.

Diagrama UML


Abstraction: define una interface abstracta. Mantiene una referencia a un objeto de tipo Implementor.
RefinedAbstraction: extiende la interface definida por Abstraction
Implementor: define la interface para la implementación de clases. Esta interface no se tiene que corresponder exactamente con la interface de Abstraction; de hecho, las dos interfaces pueden ser bastante diferentes entre sí. Típicamente la interface Implementor provee sólo operaciones primitivas, y Abstraction define operaciones de alto nivel basadas en estas primitivas.
ImplementadorConcreto: implementa la interface de Implementor y define su implementación concreta.

Abstraction emite los pedidos de los clientes a su objeto Implementor. El cliente no tiene que conocer los detalles de la implementación.

Ejemplo

Imaginemos que necesitamos dibujar distintas figuras geométricas (círculo, rectángulo, etc). Cada figura geométrica puede ser dibujada con diferentes tipos de líneas (normal, punteada, etc).

¿Que alternativas tenemos?

Por ejemplo, podría hacer una clase dibujo con todos los tipos de dibujos posibles. Pero a medida que me agreguen dibujos y formas, se va a parecer a un antipatrón (the God Class). Con esto quiere decir, que sería inmanejable.
Entonces podría hacer la clase Círculo y Rectángulo y que ellas dibujen su propia forma. Pero que pasa si me modifican el Dibujo en sí; por ejemplo, el espesor de la línea punteada tiene que se más grueso...¿porque un círculo debería tener conocimientos tan finos de dibujo?
Se podrían pensar más alternativas pero ningua terminará de satisfacer en un 100% nuestro problema. Es por ello que existe el Bridge.

Vamos a combinar las clases de tal forma que tanto un Círculo como un Rectángulo sepan como dibujarse de manera abstracta, pero le dejaremos la implementación a un especialista en dibujo.



Obviamente estas clases no debería realizar una simple salida por consola sino que debería poseer el algoritmo del dibujo, pero nos sirve a modo de ejemplo.


Bien, ya tenemos las implementaciones de ambos dibujos. Ahora veamos de utilizarlas en las clases correspondientes.


Veamos como se llama desde el cliente:



Consecuencias
  • Desacopla interface e implementación: una implementación no es limitada permanentemente a una interface. Le es posible a un objeto cambiar su implementación en tiempo de ejecución. Este desacoplamiento fomenta las capas, que pueden conducir a un sistema mejor estructurado.
  • La parte de alto nivel de un sistema sólo tiene que conocer Abstraction e Implementor.
  • Mejora la extensibilidad: se puede extender las jerarquías de Abstraction e Implementor independientemente.
  • Esconde los detalles de la implementación a los clientes

3 comentarios:

sol dijo...

cual es la clase bridge? mi profesor dice que falta la clase brige.. no es la clase Dijujo????

Max dijo...

Sol, en este patron tenes una abstraccion y un implementador. La clase Bridge como tal no existe. Saludos!

Anónimo dijo...

Pero acá hay un problema, Círculo hereda dibujarRectangulo de Forma, y lo mismo con Rectángulo que hereda dibujarCirculo.