我们何时需要适配器模式?

时间:2010-08-13 15:14:19

标签: design-patterns adapter

我们什么时候需要去适配器模式?如果可能的话,给我一个适合这种模式的真实世界的例子......

7 个答案:

答案 0 :(得分:42)

我在一个需要与外部DVR接口的系统上工作。在大多数情况下,所有DVR都具有相同的基本功能:从某个视频源开始录制;停止录音;从某个时间开始播放;停止播放等。

每个DVR制造商都提供了一个软件库,允许我们编写代码来控制他们的设备(为了便于讨论,我将其称为SDK)。即使每个SDK都提供了所有基本功能的API,但它们都不是完全相同的。这是一个非常粗略的例子,但你明白了这个想法:

  • BeginPlayback(DateTime startTime);
  • StartPlayback(long startTimeTicks);
  • 播放(字符串startDate,字符串startTime);

我们的软件需要能够与所有DVR进行交互。因此,我们不是为每个不同的SDK编写可怕的开关/案例,而是创建了我们自己的公共IDVRController接口,并将所有系统代码写入该接口:

  • 播放(DateTime startTime);

然后我们为每个SDK编写了一个不同的适配器实现,所有这些实现都实现了我们的IDVRController接口。我们使用配置文件来指定系统将连接到的DVR的类型,并使用Factory模式来实例化该DVR的IDVRController的正确实现者。

通过这种方式,适配器模式使我们的系统代码更简单:我们总是编码为IDVRController。它允许我们在部署后推出适用于新SDK的适配器(我们的Factory使用反射来实例化正确的IDVRController实例)。

答案 1 :(得分:4)

  

在计算机编程中,适配器   模式(通常称为   包装模式或只是一个包装器)   是一种翻译的设计模式   一个类的接口   兼容接口。适配器   允许类一起工作   通常不能因为   通过提供不兼容的接口   它在使用时与客户端的接口   原始界面。适配器   将对其接口的调用转换为   调用原始界面,和   必须执行的代码量   这通常很小。适配器   也负责转型   数据成适当的形式。对于   实例,如果有多个布尔值   存储为单个整数但是   你的消费者需要一个   'true'/'false',适配器将是   负责提取   来自整数的适当值   值。

alt text

Wikipedia !!!

答案 2 :(得分:3)

现有界面

var search = "Chicken Breast (200g)";
var h3 = element(by.cssContainingText('h3.product-title', search));
var button = h3.element(by.xpath('..')).element(by.css('button'));
button.click();

Shape接口的当前实现

interface Shape {
    public int calculateArea(int r);
}

现在考虑您希望Circle类适应我们现有的界面,我们无法修改(由第三方编写)。

class Square implements Shape {
    @Override
    public int calculateArea(int r) {
        return r * r;
    }
}

现在我们已经将Circle实现改编为Shape接口。所以我们需要一个适配器,因为它们是不兼容的。

class Circle {
    public double calculateCircularArea (int r) {
        return 3.14 * r * r;
    }
}

CircleAdaptor - 适用于圆形的适配器
圈 - 适应者是 形状 - 是目标接口

class CirCleAdaptor extends Circle implements Shape {
    @Override
    public int calculateArea(int r) {
        return (int) calculateCircularArea(r);
    }
}

希望这能更好地了解何时使用它。

答案 3 :(得分:3)

当您必须处理具有类似行为的不同接口时,您可以使用适配器设计模式(这通常意味着具有相似行为但具有不同方法的类)。它的一个例子是连接到三星电视的类和另一个连接到索尼电视的类。他们将分享常见的行为,如打开菜单,开始播放,连接到网络等,但每个库将有不同的实现(具有不同的方法名称和签名)。这些不同的供应商特定实现在UML图中称为 Adaptee

因此,在您的代码(在UML图中称为客户端)中,您可以创建每个供应商(或 Adaptee )的方法调用而不是硬代码一个通用接口(在UML图中称为目标)来包装这些类似的行为,并且只使用一种类型的对象。

然后适配器将实施目标接口,将其方法调用委托给传递给适配器的适应器 通过构造函数。

为了让您在Java代码中实现这一点,我使用适配器处理多个智能电视接口,使用上面提到的完全相同的示例编写了一个非常简单的项目。代码很小,文档齐全且具有解释性,因此请深入研究,看看现实世界的实现情况。

只需下载代码并将其作为Maven项目导入Eclipse(或您喜欢的IDE)。您可以通过运行 org.example.Main.java 来执行代码。请记住,重要的是要了解如何将类和接口组合在一起来设计模式。我还在 com.thirdparty.libs 包中创建了一些假的 Adaptees 。希望它有所帮助!

https://github.com/Dannemann/java-design-patterns

答案 4 :(得分:2)

以下情况需要适配器模式:

假设您已使用方法I1M1

定义了界面M2

C1C2实现此界面I1,现在C1实施M1M2您没有找到其他人的帮助现有的类,所以你需要自己编写所有逻辑。

现在,在实施课程C2时,您遇到的课程C3包含方法M3M4,可用于实施M1和{{1} {}为} M2所以要在课程C2中使用M3M4,您可以扩展课程C2并使用C3M3 } M4

在此示例中,C3变为C2Adapter class变为C3

adaptee

答案 5 :(得分:1)

适配器模式的一个非常常见的示例是通过Service Provider Interface完成的,并且通常在许多Java EE框架中使用。

它的原因是允许不同的Java EE实现,但程序员只需编写Java EE规范而不是特定于实现的代码。

与直接使用WebSphere类进行编码相反,后者将您锁定为使用WebSphere。

或者更坏(根据我的经验),Apache HTTP Client并稍后发现,因为你编码到该实现而不是正常的HttpUrlConnection,你必须进行大量的重新编码,因为它不支持当前版本的TLS如果原始开发人员编码为更稳定的API并且我们只需要升级Java运行时,就可以避免使用。

答案 6 :(得分:1)

不兼容的接口

EuroPlug 连接器仅连接到欧洲电源插座:

interface EuroPlug {
   fun plugIn()
}

class EuroSocket {
   fun supplyCurrent(plug: EuroPlug) = plug.plugIn()
}

USPlug 连接器仅连接到美国电源插座:

interface USPlug {
   fun plugIn()
}

class USSocket {
   fun supplyCurrent(plug: USPlug) = plug.plugIn()
}

创建适配器

当我们有 USSocketEuroPlug 时,我们创建一个适配器来将 EuroPlug 转换为 USPlug

class EuroToUSPlugAdapter(private val euroPlug: EuroPlug) : USPlug {
   override fun plugIn() = euroPlug.plugIn()
}

现在 EuroToUSPlugAdapter 适配现有类 USPlug 的接口 USSocket 而无需更改它。


使用适配器

这里我们有一个 USSocket 但有一个 EuroPlug 对象。因此,我们将 EuroPlug 对象传递给 EuroToUSPlugAdapter,后者执行将 EuroPlug 转换为 USPlug 的工作:

fun main() {
   val usSocket = USSocket()
   val euroPlug = object : EuroPlug {
       override fun plugIn() {
           println("Euro plug adapted for US Socket")
       }
   }
  
   val euroAdapter = EuroToUSPlugAdapter(euroPlug)
   usSocket.supplyCurrent(euroAdapter)
}

就是这样!这就是适配器模式允许两个不兼容的接口一起工作的方式。希望有所帮助。

相关问题