Diferencia entre patrón de puente y patrón de adaptador

Respuestas:

173

"El adaptador hace que las cosas funcionen después de que están diseñadas; Bridge las hace funcionar antes de que sean. [GoF, p219]"

Efectivamente, el patrón Adaptador es útil cuando tiene un código existente, ya sea de terceros o interno, pero está fuera de su control o no se puede cambiar para cumplir con la interfaz que necesita. Por ejemplo, tenemos un SuperWeaponsArray que puede controlar una buena variedad de dispositivos del día del juicio final.

public class SuperWeaponsArray {
  /*...*/

  public void destroyWorld() {
    for (Weapon w : armedWeapons) {
      w.fire();
    }
  }
}

Excelente. Excepto que nos damos cuenta de que tenemos un dispositivo nuclear en nuestro arsenal que es muy anterior a la conversión a la interfaz de armas. Pero realmente nos gustaría que funcionara aquí ... así que, ¿qué hacemos ... encajarlo?

NukeWeaponsAdaptor: basado en nuestra clase Nuke, pero exportando la interfaz de armas. Dulce, ahora seguramente podemos destruir el mundo. Parece un poco difícil, pero hace que todo funcione.


El puente patrón es algo que implementa por adelantado: si sabe que tiene dos jerarquías ortogonales, proporciona una forma de desacoplar la interfaz y la implementación de tal manera que no obtenga una cantidad increíble de clases. Digamos que tienes:

Tipos de objetos de archivo MemoryMappedFile y DirectReadFile. Supongamos que desea poder leer archivos de varias fuentes (quizás implementaciones de Linux vs. Windows, etc.). Bridge te ayuda a evitar terminar con:

MemoryMappedWindowsFile MemoryMappedLinuxFile DirectReadWindowsFile DirectReadLinuxFile

James
fuente
9
rechazado, ¿podría usar una lista de código más abstracta? El ejemplo es demasiado específico y es confuso.
36
@omouse upvoted, el código de ejemplo realmente no es lo que hace que esta respuesta vaya al grano. Para un lector cuidadoso, hay suficientes punteros para comenzar a distinguir patrones, así que, en general, es una buena respuesta.
Victor Farazdagi el
15
¿podría proporcionar algún ejemplo de código real para el patrón de puente?
Jaime Hablutzel
2
Me imagino que muchas personas llegaron a esta pregunta de la misma manera que yo: probablemente ya estaban mirando el código de los dos patrones, pero reconocieron algunas similitudes y se dieron cuenta de que su comprensión podría solidificarse aún más al yuxtaponer los dos patrones. La línea sobre el puente que le ayuda a evitar terminar con archivos específicos de Windows y Linux fue, al menos para mí, instrumental para comprender cómo el "Implementador" del Patrón de Puente ( dofactory.com/net/bridge-design-pattern ) es diferente de un "Adaptador".
Jordania
3
"El adaptador hace que las cosas funcionen después de su diseño; Bridge las hace funcionar antes de que lo sean". no se especificó en el libro que leí, por lo que fue difícil distinguirlos. Creo que leer GOF vale la pena después de todo ...
Alexander Derck
15

http://en.wikipedia.org/wiki/Adapter_pattern

El patrón del Adaptador se trata más de hacer que su código existente funcione con un sistema o interfaz más nuevos.

Si tiene un conjunto de API de servicios web estándar de la empresa que le gustaría ofrecer a la interfaz de extensibilidad existente de otra aplicación, puede considerar escribir un conjunto de adaptadores para hacerlo. Tenga en cuenta que hay un área gris y se trata más de cómo define técnicamente el patrón, ya que otros patrones como la fachada son similares.

http://en.wikipedia.org/wiki/Bridge_pattern

El patrón Bridge le permitirá posiblemente tener implementaciones alternativas de un algoritmo o sistema.

Aunque no es un ejemplo clásico de patrón de Bridge, imagínese si tuviera algunas implementaciones de un almacén de datos: una es eficiente en el espacio, la otra es eficiente en el rendimiento sin procesar ... y tiene un caso de negocios para ofrecer tanto en su aplicación como en su marco .

En términos de su pregunta, "¿dónde puedo usar qué patrón", la respuesta es, donde sea que tenga sentido para su proyecto! Quizás considere ofrecer una edición de aclaración para guiar la discusión sobre dónde cree que necesita usar uno u otro.

Jeff Wilcox
fuente
14

Adaptador:

  1. Es un patrón estructural
  2. Es útil trabajar con dos interfaces incompatibles.

Diagrama UML: del artículo de dofactory :

ingrese la descripción de la imagen aquí

Objetivo : define la interfaz específica del dominio que utiliza el Cliente.

Adaptador : adapta la interfaz Adaptado a la interfaz de destino.

Adaptado : define una interfaz existente que necesita adaptación.

Cliente : colabora con objetos que se ajustan a la interfaz de destino.

Ejemplo:

Cuadrado y Rectángulo son dos formas diferentes y obtener el área () de cada una de ellas requiere diferentes métodos. Pero todavía Square trabaja en la interfaz Rectángulo con la conversión de algunas de las propiedades.

public class AdapterDemo{
    public static void main(String args[]){
        SquareArea s = new SquareArea(4);
        System.out.println("Square area :"+s.getArea());
    }
}

class RectangleArea {
    public int getArea(int length, int width){
        return length * width;
    }
}

class SquareArea extends RectangleArea {

    int length;
    public SquareArea(int length){
        this.length = length;
    }
    public int getArea(){
        return getArea(length,length);
    }
}

Puente:

  1. Es un patrón estructural
  2. desacopla una abstracción de su implementación y ambos pueden variar independientemente
  3. Es posible porque la composición se ha utilizado en lugar de la herencia.

EDITAR: (según la sugerencia de @quasoft)

Tienes cuatro componentes en este patrón.

  1. Abstracción : define una interfaz

  2. Abstracción refinada : Implementa la abstracción:

  3. Implementador : define una interfaz para la implementación

  4. ConcreteImplementor : implementa la interfaz Implementor.

Fragmento de código:

Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();

gear = new AutoGear();
vehicle = new Car(gear);
vehicle.addGear();

Publicación relacionada:

¿Cuándo usas el patrón de puente? ¿Cómo es diferente del patrón del adaptador?

Diferencias clave: del artículo fuente

  1. El adaptador hace que las cosas funcionen después de que están diseñadas; El puente los hace trabajar antes que ellos.
  2. Bridge está diseñado por adelantado para permitir que la abstracción y la implementación varíen de forma independiente. El adaptador se actualiza para que las clases no relacionadas funcionen juntas.
Ravindra babu
fuente
Incluya el ejemplo de automóvil / camión / equipo de los documentos en la respuesta. Gran ejemplo y analogía.
cuasoft
8

Esta publicación ha existido durante bastante tiempo. Sin embargo, es importante entender que una fachada es algo similar a un adaptador, pero no es exactamente lo mismo. Un adaptador "adapta" una clase existente a una clase de cliente generalmente no compatible. Supongamos que tiene un antiguo sistema de flujo de trabajo que su aplicación está utilizando como cliente. Su compañía posiblemente podría reemplazar el sistema de flujo de trabajo con uno nuevo "incompatible" (en términos de interfaces). En la mayoría de los casos, puede usar el patrón del adaptador y escribir el código que realmente llama a las nuevas interfaces del motor de flujo de trabajo. Un puente se usa generalmente de una manera diferente. Si realmente tiene un sistema que necesita trabajar con diferentes sistemas de archivos (es decir, disco local, NFS, etc.), podría usar el patrón de puente y crear una capa de abstracción para trabajar con todos sus sistemas de archivos. Esto sería básicamente un caso de uso simple para el patrón de puente. La fachada y el adaptador comparten algunas propiedades peroLas fachadas se utilizan generalmente para simplificar una interfaz / clase existente . En los primeros días de EJB no había llamadas locales para EJB. Los desarrolladores siempre obtuvieron el trozo, lo redujeron y lo llamaron "pseudo-remotamente". Esto a menudo causó problemas de rendimiento (especialmente cuando realmente se llama por cable). Los desarrolladores experimentados usarían el patrón de fachada para proporcionar una interfaz muy gruesa al cliente. Esta fachada, a su vez, haría múltiples llamadas a diferentes métodos más específicos. En general, esto redujo en gran medida la cantidad de llamadas a métodos requeridas y aumentó el rendimiento.

John Penner
fuente
Sin embargo, aparentemente fuera del alcance de esta pregunta, ponderar Adaptador y Puente contra Fachada puede ser muy apropiado.
Cody
1

Puente mejorado Adaptador. El puente incluye un adaptador y le agrega flexibilidad adicional. Así es como los elementos del mapa de respuestas de Ravindra entre patrones:

      Adapter  |    Bridge
    -----------|---------------
    Target     | Abstraction
    -----------|---------------
               | RefinedAbstraction
               |
               |   This element is Bridge specific. If there is a group of 
               |   implementations that share the same logic, the logic can be placed here.
               |   For example, all cars split into two large groups: manual and auto. 
               |   So, there will be two RefinedAbstraction classes.
    -----------|--------------- 
    Adapter    | Implementor
    -----------|---------------
    Adaptee    | ConcreteImplementor
polina-c
fuente
1

En la respuesta superior, @James cita una oración del GoF, página 219. Creo que vale la pena reproducir la explicación completa aquí.

Adaptador contra puente

Los patrones de Adaptador y Puente tienen algunos atributos comunes. Ambos promueven la flexibilidad al proporcionar un nivel de indirección a otro objeto. Ambos implican reenviar solicitudes a este objeto desde una interfaz que no sea la suya.

La diferencia clave entre estos patrones radica en sus intenciones. El adaptador se centra en resolver incompatibilidades entre dos interfaces existentes. No se centra en cómo se implementan esas interfaces, ni considera cómo podrían evolucionar independientemente. Es una forma de hacer que dos clases diseñadas independientemente trabajen juntas sin tener que volver a implementar una u otra. Bridge, por otro lado, une una abstracción y sus implementaciones (potencialmente numerosas). Proporciona una interfaz estable para los clientes, incluso cuando le permite variar las clases que lo implementan. También admite nuevas implementaciones a medida que el sistema evoluciona.

Como resultado de estas diferencias, el Adaptador y el Puente a menudo se usan en diferentes puntos del ciclo de vida del software. A menudo se hace necesario un adaptador cuando descubre que dos clases incompatibles deberían funcionar juntas, generalmente para evitar la replicación de código. El acoplamiento es imprevisto. Por el contrario, el usuario de un puente entiende por adelantado que una abstracción debe tener varias implementaciones, y ambas pueden evolucionar independientemente. El patrón del adaptador hace que las cosas funcionen después de que están diseñadas; El puente los hace trabajar antes que ellos. Eso no significa que Adapter sea de alguna manera inferior a Bridge; cada patrón simplemente aborda un problema diferente.

jaco0646
fuente
0

Suponga que tiene una clase de forma abstracta con una funcionalidad de dibujo (genérica / abstracta) y un círculo que implementa la forma. El patrón de puente simplemente es un enfoque de abstracción bidireccional para desacoplar la implementación (dibujo en círculo) y la funcionalidad genérica / abstracta (dibujo en la clase Shape).

que significa realmente? A primera vista, suena como algo que ya está haciendo (por inversión de dependencia). Por lo tanto, no se preocupe por tener una base de código menos rígida o más modular. Pero es una filosofía un poco más profunda detrás de esto.

Según tengo entendido, la necesidad de un patrón de uso puede surgir cuando necesito agregar nuevas clases que están estrechamente relacionadas con el sistema actual (como RedCircle o GreenCircle) y que difieren en una sola funcionalidad (como el color). Y voy a necesitar un patrón de Puente particularmente si las clases del sistema existentes (Círculo o Forma) se cambian con frecuencia y no desea que las clases recién agregadas se vean afectadas por esos cambios. Es por eso que la funcionalidad de dibujo genérico se abstrae en una nueva interfaz para que pueda alterar el comportamiento del dibujo independientemente de Shape o Circle.

stdout
fuente