目录
1、什么是适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
适配器模式能够将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,要求程序员了解现有组件库中的相关组件的内部结构,且前者不符合我们六大软件设计原则中的“合成复用原则”,所以应用相对较少些。
2、为什么用适配器模式
举个很简单的例子:大家在之前的时候,会发现耳机孔是那种圆圆的耳机孔,但是发展到后来,大部分手机取消了这种圆圆的耳机孔(图一),取而代之的是将耳机头改为Type-C头(图二),和充电口共用一个口。但是如果我们这个时候想用那种圆圆的耳机孔的话,只能通过“转接头”(图三)来使用。这个转接头便是“适配器”思想。
图一
图二
图三
3、适配器模式的结构
适配器模式(Adapter)包含以下主要角色:
- 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
- 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
- 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
接下来我们会利用上述例子来讲解适配器类的实现。例子:有一部手机,只支持Type-C接口的耳机,但是我们现在拥有的是圆口耳机,因此只能用转换器来使得我们的手机能够使用圆口耳机。
4、类适配器模式代码实现
4.1 思想
实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。
4.2 代码实现
Type-C耳机接口:
public interface TypeCEarPhone { //Type-C耳机接口
public void type();//表名自己是什么类型
}
Type-C口耳机的实现类:
public class TypeCEarPhoneImpl implements TypeCEarPhone { //Type-C口耳机的实现类
@Override
public void type() {
System.out.println("我是Type-C口的耳机");
}
}
圆口耳机接口:
public interface CircularEarPhone { //圆口耳机接口
public void type();//表名自己是什么类型
}
圆口耳机的实现类:
public class CircularEarPhoneImpl implements CircularEarPhone { //圆口耳机的实现类
@Override
public void type() {
System.out.println("我是圆口的耳机");
}
}
手机类:
public class Phone { //手机类
public void useEarPhone(TypeCEarPhone earPhone){ //只支持Type-C接口的耳机
earPhone.type();//表明自己现在是什么耳机类型
}
}
测试类:
public class Test {
public static void main(String[] args) {
Phone phone = new Phone(); //new一个手机对象
CircularEarPhoneImpl earPhone = new CircularEarPhoneImpl();//此时我只有一个圆口耳机
phone.useEarPhone(earPhone); //手机来使用耳机
}
}
大家会发现,上述代码会报错:
因为我们手机仅支持Type-C口的,因此这里我们肯定无法使用圆口的耳机,因此这个时候就需要使用“转换器”来使得我们手机能够使用这个耳机了。
转换器类:
public class Adapter extends CircularEarPhoneImpl implements TypeCEarPhone {
@Override
public void type() {
super.type();
}
}
这个时候我们再来通过转换类使用耳机即可:
public class Test {
public static void main(String[] args) {
Phone phone = new Phone(); //new一个手机对象
Adapter earPhone = new Adapter();//由于转换器类继承了耳机类,相当于耳机和转换器直接连一起了
phone.useEarPhone(earPhone); //手机来使用耳机
}
}
运行结果如下:
4.3 问题分析
可见,上述我们通过“转换器”成功让我们仅支持Type-C接口的手机使用上了圆口的耳机。这种方式比较简单粗暴,直接相当于将“耳机和转换器”连接到一起使用,但是缺点很明显:耦合性太大,如果此时我们想使用的是另一个圆口耳机类,是不是就不太行了?因此我们更推荐大家使用接下来这种实现方式:对象适配器模式。当然这种方式也是更符合我们“合成复用原则”的一种实现方式。
5、对象适配器模式代码实现
5.1 思想
实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。
5.2 代码实现
这里我们手机类、圆口耳机接口、圆口耳机接口实现类、Type-C耳机接口、Type-C耳机接口实现类均和上述代码一样。唯一有变化的便是适配器类。
适配器类:
public class Adapter implements TypeCEarPhone {
private CircularEarPhone earPhone;
public Adapter(CircularEarPhone circularEarPhone){
earPhone=circularEarPhone;
}
@Override
public void type() {
earPhone.type();
}
}
测试类:
public class Test {
public static void main(String[] args) {
Phone phone = new Phone(); //new一个手机对象
CircularEarPhoneImpl circularEarPhone = new CircularEarPhoneImpl();//我们拥有的圆口耳机
Adapter adapter = new Adapter(circularEarPhone);//将圆口耳机装上"转换器"
phone.useEarPhone(adapter); //手机来使用耳机
}
}
运行结果:
可见,这种“对象适配器模式”大大减少了我们适配器和耳机的耦合度,如果此时我们拥有的是另一种圆口类型的耳机,直接传参即可,因此我们更推荐大家使用这种适配器模式。
6、适配器模式应用场景
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。