桥接模式与适配器模式的区别

桥模式和适配器模式之间的区别是什么?

71938 次浏览

Http://en.wikipedia.org/wiki/adapter_pattern

Adapter 模式更多地是关于让现有代码与较新的系统或接口一起工作。

如果您有一组公司标准的 Web 服务 API,希望提供给其他应用程序的现有扩展性接口,那么可以考虑编写一组适配器来实现这一点。请注意,这里有一个灰色区域,这更多的是关于如何在技术上定义模式,因为其他模式,如外观是相似的。

Http://en.wikipedia.org/wiki/bridge_pattern

Bridge 模式将允许您可能拥有一个算法或系统的替代实现。

尽管这不是一个典型的 Bridge 模式示例,但是想象一下如果您有一些数据存储的实现: 一个在空间上是高效的,另一个在原始性能上是高效的... ... 并且您有一个在应用程序或框架中同时提供这两种功能的业务案例。

对于您的问题“在哪里我可以使用哪种模式”,答案是,只要它对您的项目有意义!也许可以考虑提供一个澄清编辑,以指导讨论您认为您需要使用其中一个或另一个。

“适配器能让设计好的东西工作,布里奇能让它们工作 在他们之前工作。[ GoF,p219]”

实际上,当您拥有现有的代码时,适配器模式非常有用,无论是第三方代码,还是内部代码,但是不在您的控制范围内,或者在其他情况下无法更改以完全满足您所需要的接口时,适配器模式都非常有用。例如,我们有一个超级武器阵列,它可以控制一系列的末日装置。

public class SuperWeaponsArray {
/*...*/


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

很好。除了我们意识到我们的武器库里有一个核装置,它比转换成武器界面的时间要早得多。但是我们真的希望它能在这里工作... 所以我们该怎么办... 把它插进去!

核武器适配器基于我们的核武器类,但导出武器接口。太好了,现在我们可以毁灭世界了。这看起来有点像一个组件,但它使事情工作。


舰桥模式是您预先实现的——如果您知道自己有两个正交层次结构,那么它提供了一种解耦接口和实现的方法,这样您就不会得到大量的类。假设你有:

MemyMappedFile 和 DirectReadFile 类型的文件对象。假设您希望能够从各种来源读取文件(可能是 Linux 或 Windows 实现等)。Bridge 可以帮助你避免与以下人士结束关系:

记忆映射窗口文件 内存映射 LinuxFile 文件 DirectReadLinuxFile

这个帖子已经有一段时间了。但是,理解 facade 与适配器有些相似是很重要的,但它们并不完全相同。适配器将现有类“适配”到通常不兼容的客户端类。假设您有一个旧的工作流系统,您的应用程序将其用作客户端。您的公司可能会用一个新的“不兼容”的工作流系统(在接口方面)来替代工作流系统。在大多数情况下,您可以使用适配器模式并编写实际调用新工作流引擎接口的代码。桥梁通常以不同的方式使用。如果你的系统需要处理不同的文件系统(比如本地磁盘、 NFS 等) ,你可以使用桥模式并创建一个抽象层来处理所有的文件系统。这基本上是桥模式的一个简单用例。Facade 和适配器共享一些属性,但不包括 Facade 通常用于简化现有的接口/类。在 EJB 的早期,没有对 EJB 的本地调用。开发人员总是获得存根,缩小范围,并称之为“伪远程”。这常常导致性能问题(尤指。当真的通过电话呼叫时)。有经验的开发人员会使用 facade 模式为客户机提供一个非常粗粒度的接口。然后,这个 facade 将反过来对不同的更细粒度的方法执行多个调用。总之,这大大减少了所需的方法调用的数量,并提高了性能。

适配器:

  1. 这是一种结构模式
  2. 使用两个不兼容的接口是有用的

UML 图: 来自 工厂文章:

enter image description here

Target : 定义客户端使用的特定于域的接口。

Adapter : 将接口 Adaptee 适配到 Target 接口。

Adaptee : 定义需要适应的现有接口。

Client : 与符合 Target 接口的对象协作。

例如:

正方形和矩形是两种不同的形状,它们的面积()的获取需要不同的方法。但是仍然对 Square 工作的矩形界面进行了一些属性的转换。

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

驾驶台:

  1. 这是结构模式
  2. 它将抽象与其实现分离,并且两者都可以独立变化
  3. 这是可能的,因为组合已经被用来代替继承

编辑: (根据@quasoft 的建议)

这个模式有四个组成部分。

  1. 抽象 : 它定义了一个接口

  2. ReferedAbstraction : 它实现了抽象:

  3. 实现者 : 它定义了一个用于实现的接口

  4. ConcreteIntegrator : 它实现了实现者接口。

代码片段:

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


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

相关职位:

什么时候使用桥模式? 它与适配器模式有什么不同?

关键区别: 摘自 源头挖掘文章

  1. 适配器使事物在设计之后工作; 布里奇使事物在设计之前工作。
  2. 桥是预先设计的,让抽象和实现独立变化。适配器进行了改造,使不相关的类一起工作。

假设您有一个具有(通用/抽象)绘图功能的抽象形状类和一个实现形状的 Circle。桥模式只是一种双向抽象方法,用于解耦实现(在 Circle 中绘制)和通用/抽象功能(在 Shape 类中绘制)。

这到底意味着什么?乍一看,它听起来像是您已经创建的东西(通过依赖性反转)。因此,不用担心拥有一个不那么死板或更模块化的代码库。但这背后有更深层次的哲学。

根据我的理解,当我需要添加与当前系统密切相关的新类(如 RedCircle 或 GreenCircle)并且它们只有一个功能(如颜色)不同时,可能会出现使用模式的需要。我需要桥模式,特别是如果现有的系统类(圈或形状)是经常变化的,你不希望新添加的类受到这些变化的影响。因此,这就是为什么通用绘图功能被抽象到一个新的界面,以便您可以改变绘图行为独立于形状或圆。

桥是改进的适配器。桥包括适配器,并增加了额外的灵活性。 下面是拉文德拉答案中的元素如何在模式之间映射:

      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

在最上面的回答中,@James 引用了 GoF 的一句话,第219页。我认为在这里重复完整的解释是值得的。

适配器对决桥梁

Adapter 和 Bridge 模式具有一些公共属性。两者都通过向另一个对象提供一定程度的间接性来提高灵活性。两者都有 将请求从自己的接口以外的接口转发到此对象。

这些模式之间的关键区别在于它们的意图 解决两个现有接口之间的不兼容问题 这些接口是实现的,也没有考虑它们如何独立发展。这是一种让两个独立设计的类一起工作的方法 而不是重新实现其中一个。另一方面,桥接抽象及其(潜在的大量)实现。它提供了一个稳定的接口 即使它允许你改变实现它的类 随着系统的发展,会有新的实现。

由于这些差异,适配器和桥经常用在不同的地方 在软件生命周期中,适配器通常是必要的,当你发现 两个不兼容的类应该一起工作,通常是为了避免复制代码 相比之下,桥接器的用户事先就知道 抽象必须有几个实现,并且两者都可以独立发展。 适配器模式使事物工作 之后他们被设计; 桥梁使他们 工作 之前他们。这并不意味着适配器在某种程度上不如桥梁; 每个 模式只是解决了一个不同的问题。

根据另一个堆栈溢出问题的答案 给你,我觉得这个问题的答案更简洁明了:

  • Adapter 在您有一个抽象接口时使用,并且您希望使用 将该接口映射到另一个具有类似功能的对象 角色,但界面不同。

  • Bridge 与 Adapter 非常相似,但我们称之为 Bridge 定义抽象接口和底层实现。 也就是说,你不是在适应某些遗产或第三方代码,你是 所有代码的设计者,但你需要能够交换出来 不同的实现。

有很多答案可以区分适配器和桥接器。 但是当 ppl 正在寻找代码示例时,我将给出一个关于适配器设计模式的示例,它被精心制作成一个时间轴故事:

    //---------------------------------------External Vendor/Provider--------------------------------
   

//Adaptee | RussianTankInterface is adaptee | adaptee lives in is own lala land and do not care about any other class or interface
RussianTankInterface smerch9K58 = new RussianTank("The Russian Artillery bought by India in October 2015");
smerch9K58.aboutMyself();
smerch9K58.stuff();
smerch9K58.rotate();
smerch9K58.launch();
        

   

//---------------------------------2016 : India manufactures Bharat52 ------------------------------
    

//Client_1 :: IndianTank
EnemyAttacker bharat52Attacker = new IndianTank("Tank built in India delivered to Army in Jul 2016");
   

// behaves normally -------------------------(1)
bharat52Attacker.aboutMe();
bharat52Attacker.load();
bharat52Attacker.revolve();
bharat52Attacker.fireArtillery();
                

//---------------------------------2019 : India mnufactures Pinaka, and thought about fusion with Russian technology - so adaption required ------------------------------
                  

//Client_2 :: IndianTank
EnemyAttacker pinakaAttacker = new IndianTank("Tank built in India in 1998 got upgraded_v1 in 9 Sep 2019");
            

            

            

#####----Bilateral-Coalition happens----##
#####       India  : I want a fusion artillery technology with
#####                       1) Indian materials and brain-power but
#####                       2) Russian machine-parts-movement technology
#####       Russia : Give me your Interface - at max we can help by providing an Adapter
    

//---------------------------------------External Vendor/Provider-----------------------------------
    

//Adapter :: RussianTechnologyAdapter | Russia gets EnemyAttacker interface only from India & creates RussianTechnologyAdapter
RussianTechnologyAdapter russianTechnologyAdapter = new RussianTechnologyAdapter(smerch9K58);
           

           

//Target | EnemyAttacker was initially ClientInterface but later becomes the Target as story evolves | <- client owns this Interface
EnemyAttacker dhanushAttacker = russianTechnologyAdapter;
            

#####----Russia keeps her Word----##
#####       Russia to India : Here you go! Take Dhanush, a wrapper over our encapsulated adapter, and plug-in anything conforming to your EnemyAttacker.
#####       India : Thanks a lot!


//--------------------------------- 2020 : India returns back happily with dhanushAttacker---------------------------------------
            

//Client_2 - adapted behavior -------------------------(2)
dhanushAttacker.setNavigationCapability(pinakaAttacker.getCuttingEdgeNavigableTargets());
dhanushAttacker.aboutMe(); //calls RussianInstance -> aboutMyself()
dhanushAttacker.load();    //calls RussianInstance -> stuff()
dhanushAttacker.revolve(); //calls RussianInstance -> rotate()
dhanushAttacker.fireArtillery();  //calls RussianInstance -> launch()
                       

          

仔细注意:

  • (1) & (2)中相同的 API 的行为不同
  • 印度可以把大脑植入俄罗斯的线框,例如 dhanushAttacker.setNavigationCapability(pinakaAttacker.get(..))

值得注意的地方

客户方拥有:

-  Invoker /Use(uses Adapter later point)/Client
-  ClientInterface (a.k.a Target )

稍后分享:

- ClientInterface  ( becomes Target after sharing)

接收方拥有:

- Adapter (later shared directly or as a wrapper )
- Adaptee


     

希望有人也为 Bridge 提供一个内联:)

Bridge 与 Adapter 非常相似,但是当你定义抽象接口和底层实现时,我们称之为 Bridge,意思是不适应外部代码,你是所有代码的设计者,但是你需要能够交换不同的实现。

我觉得很简单。

适配器旨在允许第三方应用程序使用您的应用程序。 相反,这样您的应用程序可以与第三方应用程序一起工作。

使用桥接模式,假设它连接两个或多个应用程序,而不实现适配器。

实际上,桥是两个应用程序通过其进行交互的接口。作为桥接的一个例子,这些是 PHP 中的 PSR 接口。

例如:

其他应用

<?php


interface IRequestDataOtherApp {};
 

interface IResponseDataOtherApp {};
 

class ResponseDataOtherApp implements IResponseDataOtherApp   {


};
 

class OtherApp {
public static function request(IRequestDataOtherApp $requestData):IResponseOtherApp
{
// code
return new ResponseDataOtherApp ();
}
}

MyApp

<?php


interface IResponseDataMyApp {};


interface IReqestDataMyApp {};


class ReqestDataMyApp implements IReqestDataMyApp {};


class Adapter {
   

public static function convertResponseData(IResponseDataOtherApp $response):IResponseDataMyApp
{
      

}
public static function convertRequestData(IReqestDataMyApp $request):IRequestOtherApp
{
      

}
};
$unformattedResponse=OtherApp::request(Adapter::convertRequestData(new ReqestDataMyApp ()));
$myResponse=ResponseAdapter::convertResponseData($unformattedResponse);
//...

在前面的示例中,我们为每个请求和每个响应实现了2个适配器。 如果我们重写示例并尝试实现桥接。

<?php
interface IBridgeResponse {};

其他应用

<?php
interface IRequestDataOtherApp {};
interface IResponseDataOtherApp {};
 

class ResponseDataOtherApp  implements IBridgeResponse, IResponseDataOtherApp   {


};
 

class OtherApp {
public static function request(IRequestDataOtherApp $requestData):IResponseOtherApp
{
// code
return new ResponseDataOtherApp  ();
}
}

MyApp

<?php


interface IResponseDataMyApp {};


interface IReqestDataMyApp {};


class ReqestDataMyApp implements IReqestDataMyApp {};


class Adapter {


public static function convertResponseData(IResponseDataOtherApp $response):IResponseDataMyApp
{
      

}


public static function convertRequestData(IReqestDataMyApp $request):IRequestOtherApp
{
      

}
};


$response=OtherApp::request(Adapter::convertRequestData(new ReqestDataMyApp ()));


if($response instanceof IBridgeResponse){
/**
The component has implemented IBridgeResponse interface,
thanks to which our application can interact with it.
This is the bridge.


Our application does not have to create an additional adapter
(if our application can work with IBridgeResponse).
*/
}
//...

在六边形体系结构中,如果您从一开始就编写应用程序并准备接受正在使用的另一个应用程序的规则,那么端口(接口、合同)可以充当“桥梁”。 否则,您将不得不编写“适配器”。