design-patterns - pattern - patron proxy
¿Cuándo usas el patrón de puente? ¿Cómo es diferente del patrón del Adaptador? (11)
¿Alguien ha usado alguna vez el patrón de puente en una aplicación real? Si es así, ¿cómo lo usaste? ¿Soy yo o solo el Patrón de adaptador con una pequeña inyección de dependencia en la mezcla? ¿Realmente se merece su propio patrón?
Cuando:
A
/ /
Aa Ab
/ / / /
Aa1 Aa2 Ab1 Ab2
Refactor a:
A N
/ / / /
Aa(N) Ab(N) 1 2
El adaptador y el puente están ciertamente relacionados, y la distinción es sutil. Es probable que algunas personas que piensan que están utilizando uno de estos patrones estén usando el otro patrón.
La explicación que he visto es que Adapter se usa cuando intentas unificar las interfaces de algunas clases incompatibles que ya existen . El adaptador funciona como un tipo de traductor para implementaciones que podrían considerarse heredadas .
Mientras que el patrón Bridge se usa para código que es más probable que sea greenfield. Está diseñando Bridge para proporcionar una interfaz abstracta para una implementación que debe variar, pero también define la interfaz de esas clases de implementación.
Controladores de dispositivo es un ejemplo frecuentemente citado de Bridge, pero diría que es un Bridge si está definiendo la especificación de interfaz para proveedores de dispositivos, pero es un Adapter si toma controladores de dispositivo existentes y crea una clase contenedora para proporcionar una interfaz unificada
Entonces, en cuanto al código, los dos patrones son muy similares. En lo que respecta a los negocios, son diferentes.
Ver también http://c2.com/cgi/wiki?BridgePattern
El patrón Bridge es una aplicación del antiguo consejo, "prefiera la composición sobre la herencia". Es útil cuando debe subclasificar diferentes tiempos de forma ortogonal entre sí. Supongamos que debe implementar una jerarquía de formas coloreadas. No deberías subclasificar la Forma con Rectángulo y Círculo y luego la subclase Rectángulo con Rectángulo rojo, Rectángulo azul y Rectángulo verde e igual para Círculo, ¿o sí? Preferiría decir que cada Forma tiene un Color e implementar una jerarquía de colores, y ese es el Patrón de Puente. Bueno, yo no implementaría una "jerarquía de colores", pero entiendes la idea ...
En mi experiencia, Bridge es un patrón bastante recurrente, porque es la solución cuando hay dos dimensiones ortogonales en el dominio . Por ejemplo, formas y métodos de dibujo, comportamientos y plataformas, formatos de archivo y serializadores, etc.
Y un consejo: siempre piense en los patrones de diseño desde la perspectiva conceptual , no desde la perspectiva de implementación. Desde el punto de vista correcto, Bridge no se puede confundir con Adapter, ya que resuelven un problema diferente, y la composición es superior a la herencia no por su propio bien, sino porque permite manejar preocupaciones ortogonales por separado.
Hay una combinación de John''s respuestas de Federico''s y John''s .
Cuando:
----Shape---
/ /
Rectangle Circle
/ / / /
BlueRectangle RedRectangle BlueCircle RedCircle
Refactor a:
----Shape--- Color
/ / / /
Rectangle(Color) Circle(Color) Blue Red
He usado el patrón del puente en el trabajo. Programo en C ++, donde a menudo se lo denomina lenguaje PIMPL (indicador de implementación). Se parece a esto:
class A
{
public:
void foo()
{
pImpl->foo();
}
private:
Aimpl *pImpl;
};
class Aimpl
{
public:
void foo();
void bar();
};
En este ejemplo, la class A
contiene la interfaz y la class Aimpl
contiene la implementación.
Un uso para este patrón es exponer solo a algunos de los miembros públicos de la clase de implementación, pero no a otros. En el ejemplo, solo se puede llamar a Aimpl::foo()
través de la interfaz pública de A
, pero no a Aimpl::bar()
Otra ventaja es que puede definir Aimpl
en un archivo de encabezado separado que no necesita ser incluido por los usuarios de A
Todo lo que tiene que hacer es usar una declaración directa de Aimpl
antes de que se defina A, y mover las definiciones de todas las funciones miembro que hacen referencia a pImpl
en el archivo .cpp. Esto le da la capacidad de mantener el encabezado Aimpl
privado, y reducir el tiempo de compilación.
La intención de Bridge y Adapter es diferente y necesitamos ambos patrones por separado.
Patrón de puente:
- Es un patrón estructural
- La abstracción y la implementación no están vinculadas en el momento de la compilación
- Abstracción e implementación: ambas pueden variar sin impacto en el cliente
- Utiliza la composición sobre la herencia.
Use el patrón Bridge cuando:
- Desea el enlace en tiempo de ejecución de la implementación,
- Usted tiene una proliferación de clases resultantes de una interfaz acoplada y numerosas implementaciones,
- Desea compartir una implementación entre múltiples objetos,
- Necesita asignar jerarquías de clases ortogonales.
@ La respuesta de John Sonmez muestra claramente la efectividad del patrón del puente en la reducción de la jerarquía de clases.
Puede consultar el enlace de documentación a continuación para obtener una mejor visión del patrón de puente con el ejemplo de código
Patrón de adaptador :
- Permite que dos interfaces no relacionadas funcionen juntas a través de los diferentes objetos, posiblemente desempeñando el mismo rol.
- Modifica la interfaz original.
Diferencias clave:
- El adaptador hace que las cosas funcionen una vez que están diseñadas; Bridge los hace funcionar antes que ellos.
- Bridge está diseñado desde el principio para permitir que la abstracción y la implementación varíen de forma independiente . El adaptador está adaptado para hacer que las clases no relacionadas funcionen juntas.
- La intención: el adaptador permite que dos interfaces no relacionadas funcionen juntas. Bridge permite que la abstracción y la implementación varíen de forma independiente.
Pregunta SE relacionada con el diagrama UML y el código de trabajo:
Diferencia entre patrón de puente y patrón de adaptador
Artículos útiles:
artículo de patrón de puente fuente
artículo de patrón de adaptador de creación de fuente
artículo de patrón de puente de journaldev
EDITAR:
Ejemplo del mundo real de Bridge Pattern (según la sugerencia de meta..com, ejemplo del sitio de documentación incorporado en esta publicación ya que la documentación se va a configurar).
El patrón de puente desacopla la abstracción de la implementación para que ambos puedan variar de forma independiente. Se ha logrado con composición en lugar de herencia.
Puente patrón UML de Wikipedia:
Tienes cuatro componentes en este patrón.
Abstraction
: define una interfaz
RefinedAbstraction
: implementa la abstracción:
Implementor
: define una interfaz para la implementación
ConcreteImplementor
: Implementa la interfaz Implementor.
The crux of Bridge pattern :
dos jerarquías de clase ortogonales que usan composición (y sin herencia). La jerarquía Abstracción y la jerarquía Implementación pueden variar de forma independiente. La implementación nunca se refiere a la abstracción. Abstracción contiene la interfaz de Implementación como miembro (a través de la composición). Esta composición reduce un nivel más de jerarquía de herencia.
Caso de uso de palabra real:
Permita que diferentes vehículos tengan ambas versiones de sistema de engranaje manual y automático.
Código de ejemplo:
/* 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();
}
}
salida:
Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear
Explicación:
-
Vehicle
es una abstracción. -
Car
yTruck
son dos implementaciones concretas deVehicle
. -
Vehicle
define un método abstracto:addGear()
. -
Gear
es una interfaz implementadora -
ManualGear
yAutoGear
son dos implementaciones deGear
-
Vehicle
contiene la interfaz delimplementor
en lugar de implementar la interfaz.Compositon
de la interfaz del implementador es la clave de este patrón: permite que la abstracción y la implementación varíen de forma independiente. -
Car
yTruck
definen la implementación (abstracción redefinida) para la abstracción:addGear()
: contieneGear
- ya seaManual
oAuto
Caso (s) de uso para el patrón de puente :
- La abstracción y la implementación pueden cambiar de forma independiente entre sí y no están vinculadas en tiempo de compilación
- Asignar jerarquías ortogonales: una para la abstracción y otra para la implementación .
Para poner ejemplo de forma en el 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;
}
El resultado es:
Drawn a Square of Red Color
Drawn a Circle of Blue Color
Tenga en cuenta la facilidad con la que se pueden agregar nuevos colores y formas al sistema sin provocar una explosión de subclases debido a las permutaciones.
para mí, lo considero un mecanismo en el que puedes intercambiar interfaces. En el mundo real es posible que tenga una clase que puede usar más de una interfaz, Bridge le permite intercambiar.
Un ejemplo clásico del patrón Bridge se usa en la definición de formas en un entorno UI (ver la entrada de la Wikipedia sobre el patrón Bridge ). El patrón Bridge es un composite de los patrones de Template y Strategy .
Es una vista común de algunos aspectos del patrón de Adaptador en el patrón de Puente. Sin embargo, para citar de este artículo :
A primera vista, el patrón Bridge se parece mucho al patrón Adapter en el sentido de que una clase se usa para convertir un tipo de interfaz en otro. Sin embargo, la intención del patrón de Adaptador es hacer que las interfaces de una o más clases se vean iguales a las de una clase en particular. El patrón Bridge está diseñado para separar la interfaz de una clase de su implementación para que pueda variar o reemplazar la implementación sin cambiar el código del cliente.
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);
}
}
}