Quando você usa o padrão Bridge? Como é que é diferente do padrão Adapter?
-
11-07-2019 - |
Pergunta
Alguém já usou o Ponte Padrão em uma aplicação no mundo real? Se sim, como você usá-lo? É de mim, ou é apenas o Padrão Adapter com um pouco injeção de dependência jogado na mistura? Será que realmente merece seu próprio padrão?
Solução
Um exemplo clássico do padrão Bridge é usado na definição de formas em um ambiente UI (veja a Ponte padrão Wikipedia entrada). O padrão Bridge é um composta do < a href = "http://en.wikipedia.org/wiki/Template_method_pattern" rel = "noreferrer"> Template e padrões Estratégia .
É uma visão comum alguns aspectos do padrão Adapter no padrão Bridge. No entanto, para citar este artigo :
À primeira vista, o padrão Bridge se parece muito com o padrão Adapter em que uma classe é usado para converter um tipo de interface para outra. No entanto, a intenção do padrão Adapter é fazer com que interfaces de uma ou mais classes' olhar o mesmo que o de uma classe particular. O padrão Bridge é projetado para separar interface de uma classe a partir de sua implementação para que possa modificar ou substituir a implementação sem alterar o código do cliente.
Outras dicas
Há uma combinação de de Federico e respostas de John.
Quando:
----Shape---
/ \
Rectangle Circle
/ \ / \
BlueRectangle RedRectangle BlueCircle RedCircle
Refactor para:
----Shape--- Color
/ \ / \
Rectangle(Color) Circle(Color) Blue Red
O padrão Bridge é um aplicativo do velho conselho: "prefiro composição sobre herança". Torna-se útil quando você deve subclasse tempos diferentes de maneiras que são ortogonais entre si. Digamos que você deve implementar uma hierarquia de formas coloridas. Você não iria Forma subclasse com retângulo e círculo e, em seguida, subclasse do retângulo com redRectangle, BlueRectangle e GreenRectangle eo mesmo para Circle, você faria? Você preferiria dizer que cada Forma tem a cor e para implementar uma hierarquia de cores, e que é o padrão Bridge. Bem, eu não iria implementar uma "hierarquia de cores", mas você começa a idéia ...
Quando:
A
/ \
Aa Ab
/ \ / \
Aa1 Aa2 Ab1 Ab2
Refactor para:
A N
/ \ / \
Aa(N) Ab(N) 1 2
Adaptador e Ponte está certamente relacionado, ea distinção é sutil. É provável que algumas pessoas que pensam que eles estão usando um desses padrões estão realmente usando o outro padrão.
A explicação que eu vi é que o adaptador é usado quando você está tentando unificar as interfaces de algumas classes incompatíveis que já existe . As funções de adaptador como uma espécie de tradutor para implementações que poderiam ser consideradas legado .
Considerando que o padrão Bridge é usado para o código que é mais provável que seja greenfield. Você está projetando a ponte para fornecer uma interface abstrata para uma implementação que precisa variar, mas você também definir a interface dessas classes de implementação.
Os drivers de dispositivo é um exemplo freqüentemente citado da ponte, mas eu diria que é uma ponte se você está definindo a especificação de interface para fornecedores de dispositivos, mas é um adaptador se você está tomando drivers de dispositivo existentes e fazer um invólucro de classe para fornecer uma interface unificada.
Assim código-sábio, os dois padrões são muito semelhantes. Business-sábio, eles são diferentes.
Veja também http://c2.com/cgi/wiki?BridgePattern
Em minha experiência, a ponte é um padrão, muitas vezes recorrentes, porque é a solução sempre que existem duas dimensões ortogonais no domínio . Por exemplo. formas e métodos de desenho, comportamentos e plataformas, formatos de arquivo e serializers e assim por diante.
E um conselho: sempre pensar em padrões de projeto a partir da perspectiva conceitual , e não a partir da perspectiva de implementação. Do ponto de vista correto, Ponte não pode ser confundida com adaptador, porque eles resolver um problema diferente, ea composição é superior a herança não por causa do amor de si mesmo, mas porque permite lidar com preocupações ortogonais separadamente.
A intenção do Ponte e O adaptador é diferente e precisamos de ambos os padrões separadamente.
Ponte padrão:
- É um padrão estrutural
- Abstraction e implementação não estão vinculados em tempo de compilação
- Abstraction e implementação - ambos podem variar sem impacto no cliente
- Usa composição sobre herança.
Use o padrão Bridge quando:
- Você quer ligação da aplicação run-time,
- Você tem uma proliferação de classes resultantes de uma interface acoplada e inúmeras implementações,
- Você deseja compartilhar uma implementação entre vários objetos,
- Você precisa mapear hierarquias de classe ortogonais.
@ resposta John Sonmez mostra claramente a eficácia do padrão de ponte na redução da hierarquia de classes.
Você pode consultar abaixo link da documentação para obter uma melhor visão sobre padrão de ponte com exemplo de código
Adaptador padrão :
- permite que duas interfaces não relacionados ao trabalho em conjunto através de diferentes objetos, possivelmente jogando mesmo papel.
- Ele modifica interface original.
Principais diferenças:
- O adaptador faz as coisas funcionarem após eles são projetados; Ponte torna o trabalho antes que eles são.
- Ponte é projetado up-front para deixar o abstração e a implementação variar independentemente . Adaptador é adaptado para fazer aulas não relacionados trabalhar juntos.
- A intenção: Adaptador permite que duas interfaces independentes para trabalhar juntos. Ponte permite abstração e implementação de variar independentemente.
questão SE relacionada com UML diagrama e código de trabalho:
Diferença entre padrão Bridge e adaptador padrão
artigos úteis:
sourcemaking ponte artigo padrão
sourcemaking adaptador artigo padrão
journaldev ponte padrão
EDIT:
Padrão Ponte exemplo do mundo real (como por meta.stackoverflow.com sugestão, exemplo site da documentação incorporados neste cargo desde documentação vai sol-set)
Ponte desacopla padrão abstração da implementação de modo que ambos possam variar independentemente. Ele foi alcançado com a composição em vez de herança.
Ponte padrão UML da Wikipedia:
Você tem quatro componentes neste padrão.
Abstraction
: Define uma interface
RefinedAbstraction
: Ele implementa a abstração:
Implementor
: Define uma interface para a implementação
ConcreteImplementor
:. Ele implementa a interface Implementor
The crux of Bridge pattern :
Duas hierarquias de classe ortogonais usando composição (e nenhuma herança). A hierarquia e a hierarquia de Implementação da abstracção pode variar de forma independente. Implementação nunca se refere abstracção. Abstracção contém interface de Aplicação como um membro (através da composição). Esta composição reduz mais um nível de hierarquia de herança.
palavra real Caso de uso:
Ativar veículos diferentes para ter ambas as versões do sistema manual e engrenagem automática.
código Exemplo:
/* Implementor interface*/
interface Gear{
void handleGear();
}
/* Concrete Implementor - 1 */
class ManualGear implements Gear{
public void handleGear(){
System.out.println("Manual gear");
}
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
public void handleGear(){
System.out.println("Auto gear");
}
}
/* Abstraction (abstract class) */
abstract class Vehicle {
Gear gear;
public Vehicle(Gear gear){
this.gear = gear;
}
abstract void addGear();
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
public Car(Gear gear){
super(gear);
// initialize various other Car components to make the car
}
public void addGear(){
System.out.print("Car handles ");
gear.handleGear();
}
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
public Truck(Gear gear){
super(gear);
// initialize various other Truck components to make the car
}
public void addGear(){
System.out.print("Truck handles " );
gear.handleGear();
}
}
/* Client program */
public class BridgeDemo {
public static void main(String args[]){
Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();
gear = new AutoGear();
vehicle = new Car(gear);
vehicle.addGear();
gear = new ManualGear();
vehicle = new Truck(gear);
vehicle.addGear();
gear = new AutoGear();
vehicle = new Truck(gear);
vehicle.addGear();
}
}
saída:
Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear
Explicação:
-
Vehicle
é uma abstração. -
Car
eTruck
são duas implementações concretas deVehicle
. -
Vehicle
define um método abstrato:addGear()
. -
Gear
é implementador da interface -
ManualGear
eAutoGear
são duas implementações deGear
-
Vehicle
contém a interfaceimplementor
em vez de implementar a interface.Compositon
de interface de implementador é ponto crucial desse padrão:. Ele permite abstração e implementação para variar independentemente -
Car
eTruck
definir implementação (redefinido abstração) de abstração:addGear()
: ContémGear
- OuManual
ouAuto
Use caso (s) para o padrão Bridge :
- Abstraction e Implementação pode mudar independentes uns dos outros e eles não estão vinculados em tempo de compilação
- Mapa hierarquias ortogonais - um para Abstraction e um para Implementação .
Eu tenho usado o padrão de ponte no trabalho. Eu programa em C ++, onde muitas vezes é chamado o idioma Pimpl (ponteiro para implementação). Parece que este:
class A
{
public:
void foo()
{
pImpl->foo();
}
private:
Aimpl *pImpl;
};
class Aimpl
{
public:
void foo();
void bar();
};
Neste exemplo class A
contém a interface, e class Aimpl
contém a implementação.
Um uso para esse padrão é expor apenas algumas das membros públicos da classe de implementação, mas não outros. No exemplo apenas Aimpl::foo()
pode ser chamado através da interface pública de A
, mas não Aimpl::bar()
Outra vantagem é que você pode definir Aimpl
em um arquivo de cabeçalho separado que não precisam ser incluídos pelos usuários do A
. Tudo que você tem a fazer é usar uma declaração para a frente de Aimpl
antes A
é definido, e mover as definições de todos as funções de membro fazendo referência pImpl
no arquivo .cpp. Isto dá-lhe a capacidade de manter o cabeçalho Aimpl
privada, e reduzir o tempo de compilação.
Para colocar de forma exemplo em código:
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
class IColor
{
public:
virtual string Color() = 0;
};
class RedColor: public IColor
{
public:
string Color()
{
return "of Red Color";
}
};
class BlueColor: public IColor
{
public:
string Color()
{
return "of Blue Color";
}
};
class IShape
{
public:
virtual string Draw() = 0;
};
class Circle: public IShape
{
IColor* impl;
public:
Circle(IColor *obj):impl(obj){}
string Draw()
{
return "Drawn a Circle "+ impl->Color();
}
};
class Square: public IShape
{
IColor* impl;
public:
Square(IColor *obj):impl(obj){}
string Draw()
{
return "Drawn a Square "+ impl->Color();;
}
};
int main()
{
IColor* red = new RedColor();
IColor* blue = new BlueColor();
IShape* sq = new Square(red);
IShape* cr = new Circle(blue);
cout<<"\n"<<sq->Draw();
cout<<"\n"<<cr->Draw();
delete red;
delete blue;
return 1;
}
A saída é:
Drawn a Square of Red Color
Drawn a Circle of Blue Color
Observe a facilidade com que novas cores e formas podem ser adicionados ao sistema sem levar a uma explosão de subclasses devido à permutações.
para mim eu penso nisso como um mecanismo onde você pode trocar interfaces. No mundo real, você pode ter uma classe que pode usar mais de uma interface, ponte permite que você troque.
Bridge design pattern we can easily understand helping of service and dao layer.
Dao layer -> create common interface for dao layer ->
public interface Dao<T>{
void save(T t);
}
public class AccountDao<Account> implement Dao<Account>{
public void save(Account){
}
}
public LoginDao<Login> implement Dao<Login>{
public void save(Login){
}
}
Service Layer ->
1) interface
public interface BasicService<T>{
void save(T t);
}
concrete implementation of service -
Account service -
public class AccountService<Account> implement BasicService<Account>{
private Dao<Account> accountDao;
public AccountService(AccountDao dao){
this.accountDao=dao;
}
public void save(Account){
accountDao.save(Account);
}
}
login service-
public class LoginService<Login> implement BasicService<Login>{
private Dao<Login> loginDao;
public AccountService(LoginDao dao){
this.loginDao=dao;
}
public void save(Login){
loginDao.save(login);
}
}
public class BridgePattenDemo{
public static void main(String[] str){
BasicService<Account> aService=new AccountService(new AccountDao<Account>());
Account ac=new Account();
aService.save(ac);
}
}
}