2010-08-13 79 views
18

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

+0

您是否计划完成整本GoF书籍并询问您何时需要X模式? – 2010-08-13 15:16:03

+0

只要给他所有的upvotes,如果我是他,我会问每一个设计模式:-P – 2010-08-13 15:17:14

+0

@Thomas欧文斯:所有我所寻求的是一个很好的现实世界的例子,这将有助于我了解这种模式。 – brainless 2010-08-13 15:25:10

回答

33

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

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

  • BeginPlayback(DateTime startTime);
  • StartPlayback(long startTimeTicks);
  • 回放(string startDate,string startTime);

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

  • 播放(DateTime的开始时间);

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

这样,适配器模式使我们的系统代码变得更简单:我们始终编码为IDVRController。它允许我们在部署后部署新的SDK的适配器(我们的Factory使用反射来实例化正确的IDVRController实例)。

+1

优秀的现实生活中的例子。它帮助我理解这种模式的真正目的。我已经看到这种模式主要与服务定位器或工厂模式一起使用。 – NoobDeveloper 2013-06-19 06:37:38

5

在计算机编程,适配器 模式(通常被称为 包装图案或只是一个包装) 是转换设计模式 一个接口类为一个 兼容接口。一个适配器 允许类一起工作, 通常不能因为 不兼容接口,通过提供 其客户端接口,而使用 原始接口。适配器 将对其接口的调用转换为调用原始接口的 ,以及 执行 所需的代码量通常很小。适配器 还负责将 数据转换为适当的形式。对于 例如,如果多个布尔值 存储为一个整数,但 你的消费者需要 “真” /“假”,该适配器将 负责从整 值提取 适当的值。

alt text

Wikipedia

2

需要在以下情形适配器模式:

说你有定义的接口I1与方法M1M2

C1C2实现了这个接口I1,现在C1同时实施M1M2你有找不到其他现有类的帮助,所以你需要自己编写所有逻辑。

现在,而实现类C2你所遇到C3类可用于实现M1M2C2所以利用在课堂上那些M3M4C2你扩展C3类和使用方法M3M4M3M4C3

在这个例子中C2变得Adapter classC3成为adaptee

package com.design.patterns; 

public class AdapterExample { 
    public static void main(String[] args) { 
     Shape line = new LineShape(); 
     line.draw(); 

     Shape text = new TextShape(); 
     text.draw(); 
    } 
} 

//==Start from here 
interface Shape{ 
    public void draw(); 
} 

class LineShape implements Shape{ 
    @Override 
    public void draw() { 
     System.out.println("write some logic and draw line"); 
    } 
} 

//Adapter 
class TextShape extends TextView implements Shape{ 
    @Override 
    public void draw() { 
     System.out.println("logic is already there in class TextView"); 
     drawText(); 
    } 
} 

// Adaptee 
class TextView{ 
    public void drawText() { 
     System.out.println("Drawing Text Shape"); 
    } 
} 
1

现有的接口

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

电流Shape接口实现

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

现在考虑你希望Circle类适应我们现有的界面,而我们不能修改(由第三方书写)。

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

现在我们已经将Circle实现调整到了我们的Shape界面。所以我们需要一个适配器,因为它们不兼容。

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

CircleAdaptor - 是圆
圈适配器 - 是适配者
形状 - 是目标接口

public class AdapterPattern { 
    public static void main(String[] args) { 
     Shape circle = new CirCleAdaptor(); 
     System.out.println("Circle Area " + circle.calculateArea(5)); 
     Shape square = new Square(); 
     System.out.println("Square Area " + square.calculateArea(5)); 
    } 
} 

希望这给有关何时使用一个更好的主意。

1

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

所以,在你的代码(称为客户在UML图),而不是硬编码每个供应商的方法调用(或适配者),然后你可以创建一个通用的接口(称为目标在UML图)来包装这些类似的行为,并只使用一种类型的对象。

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

为你实现这在Java代码中,我写了使用完全相同上面使用的适配器来处理多个智能电视的接口中提到的相同的例子非常简单的项目。代码很小,有据可查,并且可以自我解释,因此请仔细阅读以查看真实世界实现的外观。

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

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

0

适配器模式的一个非常常见的例子是通过Service Provider Interface完成,在很多的Java EE框架的常用。

它的原因是为了让Java EE的不同实现,但程序员只是代码到Java EE规范而不是一些具体实施。

与之相对类似的编码,直接使用该锁你进入使用WebSphere的WebSphere类。

或者更糟糕的(从我的经验),Apache HTTP客户端,后来发现,因为你编码的实现,而不是正常的HttpUrlConnection,你必须做很多重新编码,因为它不支持当前版本的TLS如果原始开发人员编码为更稳定的API并且我们只需要升级Java运行时就可以避免。

相关问题