一、简介
适配器模式是一种结构型模式,它可以将一个类的接口转成用户期望的另外一个接口。也就是当我们想使用一个已经存在的类时,如果它的接口,也就是它的方法和我们的要求不同时,可以考虑使用适配器模式。以原有的类提供的接口(即向外暴露的方法)作为适配器的输入,适配器内部经过额外处理,向外暴露用户所需的目标接口。
适配器模式的作用是使得原本由于接口不匹配而不能一起工作的那些类可以一起工作,就比如:
- 手机想要投影到投影仪上,但手机向外提供的是Type-c接口,而投影仪需要的是VGA接口,由于接口不匹配就不能直接投影。这时候,就需要定义一个适配器,接收Type-c接口输出的视频信号作为输入,并转换输出到VGA接口,才能和投影仪对接。所以通过适配器实现了原本由于接口不匹配而不能一起工作的手机和投影仪可以一起工作
如图所示,Client不能直接访问Adaptee。Adapter是适配器,它将Adaptee转换成Client能访问的接口。所以通过适配器Adapter,用户端就可以访问Adaptee
需要注意的是我们在设计之初,就应该统一接口。或者发现接口不匹配时无法使用时,及时通过重构统一接口。最后才考虑使用适配器模式进行转换。当然,当我们维护或者复用一些老旧代码时,可以考虑使用适配器模式,在不修改原有代码上将旧的接口转换成新的目标接口,减小工作量,同时满足开闭原则。
二、应用场景
对于来源于不同数据源(即不同数据库)中的数据,这些数据在组织上可能不同,如果我们希望最终读取到的数据的格式是相同的,这时候就可以采用适配器进行转换,如将不同数据源的数据以统一的格式读出,或将统一格式的数据以对应的格式存入到对应的数据库当中。
通过使用适配器可以使我们不必关注不同数据库的数据细节,便于灵活使用数据。
在.NET中就有一个类库实现了这样的适配器,它就是DataAdapter。它用作DataSet和数据源之间的适配器以便检索和保存数据。DataAdapter通过映射Fill(更改DataSet中的数据以便能够与数据源中的数据格式相匹配)和Update(更改数据源中的数据以便能够与DataSet中的数据匹配)来提供这一适配器。其中DataSet就相当于同一的数据格式。
三、举例
一个只提供typec接口的手机通过适配器连接到需要vga接口的投影仪的过程
public class 适配器模式 {
public static void main(String[] args) {
//我们有一台手机
Phone phone=new Phone();
//想要将它连接到投影仪,首选让它更适配器连接
Adapter adapter=new Adapter(phone);
//投影仪使用适配器提供的Vga接口
adapter.vgaInterface();
}
}
//原有的类
class Phone{
//手机对外提供的接口,投影仪无法直接调用
public void typecInterface() {
System.out.println("信息从Typec口的手机输出");
}
}
//定义一个投影仪需要的目标接口
interface Vga{
void vgaInterface();
}
/*
* 定义一个适配器,能够调用手机提供的typec接口,并向外暴露vga接口, 有两种方法:
* 一是使用继承复用(即让适配器继承Phone,以便能够使用Phone提供的typec接口)
* 二是使用组合复用(即适配器内部包含一个Phone的实例作为成员对象)
* 根据合成复用原则,尽量使用组合复用,少使用继承复用,因此这里我们选择使用组合复用
*/
class Adapter implements Vga{
private Phone phone;
public Adapter(Phone phone){
this.phone=phone;
}
@Override
public void vgaInterface() {
phone.typecInterface();
System.out.println("接收到Type-c口信息,信息转换成VGA接口中...");
System.out.println("信息已转换成VGA接口,投影仪可以对接。");
}
}