我们什么时候需要去适配器模式?如果可能的话,给我一个适合这种模式的真实世界的例子......
答案 0 :(得分:42)
我在一个需要与外部DVR接口的系统上工作。在大多数情况下,所有DVR都具有相同的基本功能:从某个视频源开始录制;停止录音;从某个时间开始播放;停止播放等。
每个DVR制造商都提供了一个软件库,允许我们编写代码来控制他们的设备(为了便于讨论,我将其称为SDK)。即使每个SDK都提供了所有基本功能的API,但它们都不是完全相同的。这是一个非常粗略的例子,但你明白了这个想法:
我们的软件需要能够与所有DVR进行交互。因此,我们不是为每个不同的SDK编写可怕的开关/案例,而是创建了我们自己的公共IDVRController接口,并将所有系统代码写入该接口:
然后我们为每个SDK编写了一个不同的适配器实现,所有这些实现都实现了我们的IDVRController接口。我们使用配置文件来指定系统将连接到的DVR的类型,并使用Factory模式来实例化该DVR的IDVRController的正确实现者。
通过这种方式,适配器模式使我们的系统代码更简单:我们总是编码为IDVRController。它允许我们在部署后推出适用于新SDK的适配器(我们的Factory使用反射来实例化正确的IDVRController实例)。
答案 1 :(得分:4)
在计算机编程中,适配器 模式(通常称为 包装模式或只是一个包装器) 是一种翻译的设计模式 一个类的接口 兼容接口。适配器 允许类一起工作 通常不能因为 通过提供不兼容的接口 它在使用时与客户端的接口 原始界面。适配器 将对其接口的调用转换为 调用原始界面,和 必须执行的代码量 这通常很小。适配器 也负责转型 数据成适当的形式。对于 实例,如果有多个布尔值 存储为单个整数但是 你的消费者需要一个 'true'/'false',适配器将是 负责提取 来自整数的适当值 值。
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 。希望它有所帮助!
答案 4 :(得分:2)
以下情况需要适配器模式:
假设您已使用方法I1
和M1
M2
C1
和C2
实现此界面I1
,现在C1
实施M1
和M2
您没有找到其他人的帮助现有的类,所以你需要自己编写所有逻辑。
现在,在实施课程C2
时,您遇到的课程C3
包含方法M3
和M4
,可用于实施M1
和{{1} {}为} M2
所以要在课程C2
中使用M3
和M4
,您可以扩展课程C2
并使用C3
和M3
} M4
。
在此示例中,C3
变为C2
,Adapter 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()
}
当我们有 USSocket
和 EuroPlug
时,我们创建一个适配器来将 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)
}
就是这样!这就是适配器模式允许两个不兼容的接口一起工作的方式。希望有所帮助。