适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
在生活中,我们的笔记本电脑经常需要连接很多外部设备,有时遇见电脑提供的接口与外设接口不一致。如视频接口,现在超薄笔记本提供的都是HDMI接口,但是连接到比较老的投影仪时需要VGA接口。此时我们需要一个HDMI和VGA的转换器。如下图:

适配器模式有类的适配器模式和对象的适配器模式两种不同的形式。如下图:

上图中,左边是类的适配器模式(通过继承实现,即extends关键字),右边是对象的适配器模式(通过对象组合实现)。
类的适配器模式把被适配的类的API转换成为目标类的API,其静态结构如下图:

从上图可以看出,Adaptee类并没有showInfo()方法,而客户端则其他这个方法。为使客户端能够使用Adaptee类,提供一个中间类Adapter,把Adaptee的API与Traget类的API衔接起来。Adapter与Adaptee是继承关系,这决定了这个适配器模式是类模式。
模式所涉及的角色有:
目标(Target)角色:这是我们所期待得到的接口,注意:由于这里讨论的是类适配器模式,因此目标不可以是类。
源(Adaptee)角色:现有需要适配的接口。
适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。
Java代码如下:
// 适配器接口
public interface Target {
// 原样的将信息输出
public void show(String message);
}
// 被适配对象
public class Adaptee {
public void showInfo(String message) {
System.out.println("Adaptee=" + message);
}
}
// 具体的适配器
public class Adapter extends Adaptee implements Target {
@Override
public void show(String message) {
System.out.println("Adapter=" + message);
super.showInfo(message);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Target target = new Adapter();
target.show("hello adapter.");
}
}对象的适配器模式把被适配的类的API转换成目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。如下图:

从上图中可以看出,Adaptee类并没有show()方法,而客户端则期待这个方法。为了使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adapter与Adaptee是委派关系,这决定了这个适配器模式是对象的。
对象适配器模式设计的角色:
目标(Target)角色:这是所期待的接口,目标可以是具体的或抽象类。
源(Adaptee)角色:现有需要适配的接口。
适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口,显然,这一角色必须是具体类。
Java代码如下:
// 适配器接口
public interface Target {
// 原样的将信息输出
public void show(String message);
}
// 被适配对象
public class Adaptee {
public void showInfo(String message) {
System.out.println("Adaptee=" + message);
}
}
// 具体的适配器
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void show(String message) {
System.out.println("Adapter=" + message);
this.adaptee.showInfo(message);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Target target = new Adapter(new Adaptee());
target.show("hello adapter.");
}
}