Answers:
什么时候:
----Shape---
/ \
Rectangle Circle
/ \ / \
BlueRectangle RedRectangle BlueCircle RedCircle
重构为:
----Shape--- Color
/ \ / \
Rectangle(Color) Circle(Color) Blue Red
Bridge模式是旧建议“优先于继承而不是继承”的应用。当您必须以彼此正交的方式将不同的时间子类化时,它将变得很方便。假设您必须实现彩色形状的层次结构。您不会将Rectangle和Circle子类化为Shape,然后将RedRectangle,BlueRectangle和GreenRectangle子化为Rectangle,对Circle进行子类化,是吗?您可能想说每个Shape 都有一个Color并实现颜色的层次结构,这就是Bridge Pattern。好吧,我不会实现“颜色层次结构”,但是您知道了...
什么时候:
A
/ \
Aa Ab
/ \ / \
Aa1 Aa2 Ab1 Ab2
重构为:
A N
/ \ / \
Aa(N) Ab(N) 1 2
Adapter和Bridge当然是相关的,并且区别是微妙的。可能有些人以为自己正在使用其中一种模式,实际上正在使用另一种模式。
我看到的解释是,当您尝试统一一些已经存在的不兼容类的接口时,将使用Adapter 。适配器充当可以被认为是遗留的实现的转换器。
而桥接模式用于代码的可能性更高。您正在设计Bridge,以为需要变化的实现提供抽象接口,但是您还定义了这些实现类的接口。
设备驱动程序是Bridge经常被引用的示例,但是如果您要为设备供应商定义接口规范,那我就说它是Bridge,但是如果您要使用现有的设备驱动程序并创建包装器类,则它是Adapter。提供统一的界面。
在代码方面,这两种模式非常相似。从业务角度来看,它们是不同的。
的意图桥和适配器是不同的,我们需要分别两个模式。
桥接模式:
在以下情况下使用桥接模式:
@ John Sonmez的答案清楚地表明了桥接模式在减少类层次结构方面的有效性。
您可以参考下面的文档链接,以通过代码示例更好地了解桥接模式
适配器模式:
主要区别:
相关的SE问题与UML图和工作代码:
有用的文章:
制作桥梁模式文章
来源制作适配器模式文章
journaldev桥接模式文章
编辑:
桥接模式的真实示例(根据meta.stackoverflow.com的建议,由于文档即将落山,因此本文中并入了文档站点示例)
桥接模式将抽象与实现分离,因此两者可以独立变化。它是通过组合而不是继承来实现的。
维基百科的桥接模式UML:
在此模式中,您有四个组成部分。
Abstraction
:它定义一个接口
RefinedAbstraction
:它实现了抽象:
Implementor
:它定义了一个实现接口
ConcreteImplementor
:它实现了Implementor接口。
The crux of Bridge pattern :
两个正交的类层次结构使用组合(并且没有继承)。抽象层次结构和实现层次结构可以独立变化。实现从不引用抽象。抽象包含实现接口作为成员(通过组合)。这种组合减少了继承层次结构的另一个层次。
实词用例:
使不同的车辆同时具有手动和自动变速系统版本。
示例代码:
/* 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();
}
}
输出:
Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear
说明:
Vehicle
是一个抽象。 Car
和Truck
是的两个具体实现Vehicle
。Vehicle
定义一个抽象方法:addGear()
。Gear
是实现者接口ManualGear
和AutoGear
是两种实现 Gear
Vehicle
包含implementor
接口,而不是实现接口。Compositon
实现者接口的概念是这种模式的关键:它允许抽象和实现独立变化。 Car
并Truck
为抽象定义实现(重新定义的抽象)addGear()
::它包含 Gear
- Manual
或Auto
桥接模式的用例:
我在工作中使用了桥接模式。我使用C ++进行编程,通常将其称为PIMPL习惯用法(实现的指针)。看起来像这样:
class A
{
public:
void foo()
{
pImpl->foo();
}
private:
Aimpl *pImpl;
};
class Aimpl
{
public:
void foo();
void bar();
};
在此示例中,class A
包含接口并class Aimpl
包含实现。
此模式的一种用途是仅公开实现类的一些公共成员,而不公开其他一些。在该示例中,只能Aimpl::foo()
通过的公共接口调用A
,但不能通过Aimpl::bar()
另一个好处是,您可以Aimpl
在一个单独的头文件中定义,而头文件无需由的用户定义A
。您所要做的就是使用Aimpl
before的前向声明A
,并将引用的所有成员函数的定义移到pImpl
.cpp文件中。这使您能够保留Aimpl
标头的私有性,并减少编译时间。
将形状示例放入代码中:
#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;
}
输出为:
Drawn a Square of Red Color
Drawn a Circle of Blue Color
请注意,可以轻松地将新的颜色和形状添加到系统中,而不会由于置换而导致子类激增。
您正在一家保险公司工作,在那儿您可以开发一种工作流应用程序,该应用程序可以管理各种任务:会计,合同,索赔。这是抽象。在实现方面,您必须能够从不同的来源创建任务:电子邮件,传真,电子消息。
您可以从以下类开始设计:
public class Task {...}
public class AccountingTask : Task {...}
public class ContractTask : Task {...}
public class ClaimTask : Task {...}
现在,由于必须以特定方式处理每个源,因此您决定专门化每个任务类型:
public class EmailAccountingTask : AccountingTask {...}
public class FaxAccountingTask : AccountingTask {...}
public class EmessagingAccountingTask : AccountingTask {...}
public class EmailContractTask : ContractTask {...}
public class FaxContractTask : ContractTask {...}
public class EmessagingContractTask : ContractTask {...}
public class EmailClaimTask : ClaimTask {...}
public class FaxClaimTask : ClaimTask {...}
public class EmessagingClaimTask : ClaimTask {...}
您最终有13个班级。添加任务类型或源类型变得具有挑战性。通过使用桥模式,通过将任务(抽象)与源解耦(这是实现方面的关注点),可以轻松维护一些东西:
// Source
public class Source {
public string GetSender();
public string GetMessage();
public string GetContractReference();
(...)
}
public class EmailSource : Source {...}
public class FaxSource : Source {...}
public class EmessagingSource : Source {...}
// Task
public class Task {
public Task(Source source);
(...)
}
public class AccountingTask : Task {...}
public class ContractTask : Task {...}
public class ClaimTask : Task {...}
现在,添加任务类型或源变得更加容易。
注意:大多数开发人员不会预先创建13类层次结构来处理此问题。但是,在现实生活中,您可能不预先知道源和任务类型的数量。如果您只有一个来源和两种任务类型,则可能不会将Task与Source分离。然后,随着添加新的来源和任务类型,总体复杂性也随之增加。在某个时候,您将进行重构,并且通常会得到类似桥梁的解决方案。
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);
}
}
}