Diferença entre o padrão Bridge e o adaptador

125

Qual é a diferença entre os padrões Bridge e Adapter?

Firoz
fonte
Talvez considere oferecer uma edição de esclarecimentos para orientar a discussão sobre onde você acredita que precisa usar um ou outro.
Jeff Wilcox
Nenhuma explicação aqui jamais substituirá a leitura de Design Patterns: Elementos de Software Orientado a Objetos Reutilizáveis
lealceldeiro

Respostas:

173

"O adaptador faz as coisas funcionarem depois de projetadas; o Bridge as faz funcionar antes de serem. [GoF, p219]"

Efetivamente, o padrão do Adaptador é útil quando você possui código existente, seja de terceiros ou interno, mas fora do seu controle ou não é mutável para atender perfeitamente à interface que você precisa. Por exemplo, temos um SuperWeaponsArray que pode controlar uma boa variedade de dispositivos do dia do juízo final.

public class SuperWeaponsArray {
  /*...*/

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

Ótimo. Exceto que percebemos que temos um dispositivo nuclear em nosso arsenal que antecede amplamente a conversão para a interface de armas. Mas nós realmente gostaríamos que funcionasse aqui ... então o que fazemos?

NukeWeaponsAdaptor - baseado em nossa classe Nuke, mas exportando a interface Arma. Doce, agora podemos certamente destruir o mundo. Parece um pouco de confusão, mas faz as coisas funcionarem.


O padrão Bridge é algo que você implementa antecipadamente - se você sabe que possui duas hierarquias ortogonais, ele fornece uma maneira de dissociar a interface e a implementação de tal maneira que você não obtém um número insano de classes. Digamos que você tenha:

Tipos de objetos de arquivo MemoryMappedFile e DirectReadFile. Digamos que você queira ler arquivos de várias fontes (talvez implementações Linux vs. Windows, etc.). O Bridge ajuda a evitar que você acabe com:

MemoryMappedWindowsFile MemoryMappedLinuxFile DirectReadWindowsFile DirectReadLinuxFile

James
fonte
9
com voto negativo, você poderia usar uma listagem de código mais abstrata? o exemplo é muito específico e é confuso.
36
@omouse votou, o código de exemplo não é realmente o que faz essa resposta ao ponto. Para um leitor cuidadoso, existem indicadores suficientes para começar a distinguir padrões, de modo geral - é uma boa resposta.
21410 Victor Farazdagi
15
você poderia fornecer algum exemplo de código real para o padrão de ponte?
Jaime Hablutzel
2
Imagino que muitas pessoas chegaram a essa pergunta da mesma maneira que eu - elas provavelmente já estavam analisando o código para os dois padrões, mas reconheceram algumas semelhanças e perceberam que seu entendimento poderia ser mais solidificado justapondo os dois padrões. A linha sobre o bridge, ajudando você a evitar a conclusão de arquivos específicos do Windows e Linux, foi, pelo menos para mim, fundamental para entender como o "Implementador" do Bridge Pattern ( dofactory.com/net/net/bridge-design-pattern ) é diferente de um "Adaptador".
Jordânia
3
"O adaptador faz as coisas funcionarem depois de projetadas; o Bridge as faz funcionar antes de serem". não foi especificado no livro que li, por isso foi difícil distinguir os dois. Acho que ler o GOF vale a pena o esforço, afinal ...
Alexander Derck 31/08
15

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

O padrão do adaptador é mais sobre como fazer com que seu código existente funcione com um sistema ou interface mais recente.

Se você possui um conjunto de APIs de serviço da web padrão da empresa que gostaria de oferecer à interface de extensibilidade existente de outro aplicativo, considere escrever um conjunto de adaptadores para fazer isso. Observe que há uma área cinza e isso é mais sobre como você define tecnicamente o padrão, pois outros padrões como a fachada são semelhantes.

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

O padrão Bridge permitirá que você possua implementações alternativas de um algoritmo ou sistema.

Embora não seja um exemplo clássico de padrão de ponte, imagine se você tivesse algumas implementações de um armazenamento de dados: uma é eficiente no espaço, a outra é eficiente no desempenho bruto ... e você tem um caso de negócios para oferecer tanto no aplicativo quanto na estrutura .

Em termos de sua pergunta, "onde posso usar qual padrão", a resposta é: onde quer que faça sentido para o seu projeto! Talvez considere oferecer uma edição de esclarecimentos para orientar a discussão sobre onde você acredita que precisa usar um ou outro.

Jeff Wilcox
fonte
14

Adaptador:

  1. É um padrão estrutural
  2. É útil trabalhar com duas interfaces incompatíveis

Diagrama UML: do artigo dofactory :

insira a descrição da imagem aqui

Alvo : define a interface específica do domínio que o Cliente usa.

Adaptador : adapta a interface Adaptado à interface de destino.

Adaptado : define uma interface existente que precisa ser adaptada .

Cliente : colabora com objetos em conformidade com a interface Target.

Exemplo:

Quadrado e Retângulo são duas formas diferentes e a área de obtenção () de cada uma delas exige métodos diferentes. Mas ainda assim o Square trabalha na interface Retangular com a conversão de algumas das propriedades.

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);
    }
}

Ponte:

  1. É padrão estrutural
  2. dissocia uma abstração de sua implementação e ambas podem variar independentemente
  3. É possível porque a composição foi usada no lugar da herança

EDIT: (conforme sugestão @quasoft)

Você tem quatro componentes neste padrão.

  1. Abstração : define uma interface

  2. RefinedAbstraction : Implementa abstração:

  3. Implementador : define uma interface para implementação

  4. ConcreteImplementor : Implementa a interface do implementador.

Fragmento de código:

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

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

Post relacionado:

Quando você usa o padrão de ponte? Como é diferente do padrão do adaptador?

Principais diferenças: do artigo de criação de código - fonte

  1. O adaptador faz as coisas funcionarem após serem projetadas; Bridge os faz trabalhar antes deles.
  2. O Bridge é projetado antecipadamente para permitir que a abstração e a implementação variem independentemente. O adaptador é adaptado para fazer com que classes não relacionadas funcionem juntas.
Ravindra babu
fonte
Inclua o exemplo de carro / caminhão / equipamento dos documentos na resposta. Ótimo exemplo e analogia.
quasoft
8

Este post já existe há algum tempo. No entanto, é importante entender que uma fachada é um pouco semelhante a um adaptador, mas não é exatamente a mesma coisa. Um adaptador "adapta" uma classe existente a uma classe cliente geralmente não compatível. Digamos que você tenha um sistema de fluxo de trabalho antigo que seu aplicativo está usando como cliente. Sua empresa poderia substituir o sistema de fluxo de trabalho por um novo "incompatível" (em termos de interfaces). Na maioria dos casos, você pode usar o padrão do adaptador e escrever um código que realmente chama as interfaces do novo mecanismo de fluxo de trabalho. Uma ponte é geralmente usada de uma maneira diferente. Se você realmente possui um sistema que precisa trabalhar com sistemas de arquivos diferentes (por exemplo, disco local, NFS etc.), pode usar o padrão de ponte e criar uma camada de abstração para trabalhar com todos os seus sistemas de arquivos. Basicamente, esse seria um caso de uso simples para o padrão de ponte. A Fachada e o adaptador compartilham algumas propriedades, masfachadas são geralmente usadas para simplificar uma interface / classe existente . Nos primeiros dias dos EJBs, não havia chamadas locais para EJBs. Os desenvolvedores sempre obtinham o esboço, o reduziam e o chamavam de "pseudo-remotamente". Isso muitas vezes causava problemas de desempenho (especialmente quando realmente chamado por fio). Desenvolvedores experientes usariam o padrão de fachada para fornecer uma interface de granulação mais grossa para o cliente. Essa fachada, por sua vez, fazia várias chamadas para diferentes métodos mais refinados. Em suma, isso reduziu bastante o número de chamadas de método necessárias e aumentou o desempenho.

John Penner
fonte
Embora, aparentemente fora do escopo desta questão, a ponderação do Adaptador e Ponte contra Fachada possa ser muito apropriada.
Cody
1

Bridge é um adaptador aprimorado. O Bridge inclui adaptador e adiciona flexibilidade adicional a ele. Aqui está como os elementos da resposta de Ravindra são mapeados entre os padrões:

      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
fonte
1

Na resposta principal, @James cita uma frase do GoF, página 219. Acho que vale a pena reproduzir a explicação completa aqui.

Adaptador versus Bridge

Os padrões do adaptador e da ponte têm alguns atributos comuns. Ambos promovem flexibilidade, fornecendo um nível de indireção para outro objeto. Ambos envolvem encaminhamento de pedidos para esse objeto a partir de uma interface diferente da sua.

A principal diferença entre esses padrões reside em suas intenções. O adaptador se concentra na resolução de incompatibilidades entre duas interfaces existentes. Ele não se concentra em como essas interfaces são implementadas, nem considera como elas podem evoluir independentemente. É uma maneira de fazer com que duas classes projetadas independentemente funcionem juntas, sem reimplementar uma ou outra. Bridge, por outro lado, une uma abstração e suas (potencialmente numerosas) implementações. Ele fornece uma interface estável para os clientes, ao mesmo tempo em que permite variar as classes que o implementam. Também acomoda novas implementações à medida que o sistema evolui.

Como resultado dessas diferenças, o Adapter e o Bridge são frequentemente usados ​​em diferentes pontos do ciclo de vida do software. Um adaptador geralmente se torna necessário quando você descobre que duas classes incompatíveis devem funcionar juntas, geralmente para evitar a replicação do código. O acoplamento é imprevisto. Por outro lado, o usuário de uma ponte entende de antemão que uma abstração deve ter várias implementações e ambas podem evoluir independentemente. O padrão do adaptador faz as coisas funcionarem após serem projetadas; Bridge os faz trabalhar antes deles. Isso não significa que o adaptador seja de alguma forma inferior ao Bridge; cada padrão apenas trata de um problema diferente.

jaco0646
fonte
0

Suponha que você tenha uma classe Shape abstrata com uma funcionalidade de desenho (genérica / abstrata) e um Circle que implementa a Shape. O padrão de ponte é simplesmente uma abordagem de abstração bidirecional para dissociar a implementação (desenho em Círculo) e a funcionalidade genérica / abstrata (desenho na classe Forma).

O que isso realmente significa? À primeira vista, parece algo que você já está fazendo (por inversão de dependência). Portanto, não se preocupe em ter uma base de código menos modular ou mais modular. Mas é uma filosofia um pouco mais profunda por trás disso.

Pelo que entendi, a necessidade do padrão de uso pode surgir quando eu precisar adicionar novas classes que estão intimamente relacionadas ao sistema atual (como RedCircle ou GreenCircle) e que diferem apenas por uma única funcionalidade (como cor). E precisarei do padrão Bridge, especialmente se as classes de sistema existentes (Circle ou Shape) forem alteradas com frequência e você não quiser que as classes recém-adicionadas sejam afetadas por essas alterações. É por isso que a funcionalidade genérica do desenho é abstraída para uma nova interface, para que você possa alterar o comportamento do desenho independentemente de Shape ou Circle.

stdout
fonte