0. 前言
小弟前一部手机是安卓系统的Vivo手机,现在的手机是肾6(iphone 6),大家都知道,安卓充电线的接口和苹果充电线的接口是不同的。那么问题来了,因为我只有一条苹果的充电线,但是我白天在实验室,晚上在宿舍,那我又不想把这条线带来带去,有时候还会忘记带。怎么解决?新买一条线吗?再买一条线略贵,这时候我想起了我有一条安卓的充电线,想要废物利用,于是我去淘宝买了一个东东可以将安卓充电线接口转成苹果可以用的充电线接口。
好了,场景搭建完毕,是时候引出主角了,那就是适配器(Adapter)模式。其实上面就是一个适配器模式的使用场景,我有安卓充电线,我有苹果手机,然而它们两个并不适配,于是我买了一个可以将安卓充电线接口转成苹果可以用的充电线接口的东东,而这个东东便是适配器。
1.适配器模式
1.1 定义
将一个类的接口转换成用户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作。
1.2 结构图
适配器模式的结构一般如下图所示,这个图出自《Head First 设计模式》
下面就解释一下上图的东西
- Client:客户端,调用自己需要的接口Target中的功能。
- Target:定义了客户端需要调用的功能的接口。
- Adaptee:已经存在的接口,能满足客户端需要的功能,但由于接口与客户端要求的接口不兼容,需要被适配。
- Adapter:适配器,把Adaptee适配成Client能够使用的Target。
1.3 优点
- 复用。当一个功能已经辛辛苦苦实现了,却发现因为接口不兼容而不能使用,难道就这样不要这个功能了嘛,这不是太浪费了,所以就需要适配器模式来废物利用
- 扩展。一个适配器可以适配多个模块,很自然地就可以扩展功能。
2. 使用适配器模式
2.1 问题
就用我一开始提到的手机充电线问题,使用适配器模式用代码来描述一遍。
2.2 安卓手机用安卓线(正常使用)
这是一个安卓充电线的接口,有一个充电方法,注意这是Java接口并不是现实世界的充电接口
public interface AndroidWire {
//充电方法
void charge();
}
安卓充电线实现类
public class AndroidWireImpl implements AndroidWire{
@Override
public void charge() {
System.out.println("我是安卓充电线的实现,可 以给安卓手机充电哟~");
}
}
我的Vivo安卓手机就可以用上面的充电线了
public class Vivo {
public static void main(String[] args) {
AndroidWire wire = new AndroidWireImpl();
wire.charge();
}
}
结果
我是安卓充电线的实现,可 以给安卓手机充电哟~
2.3 苹果手机用苹果线(正常使用)
同安卓一样,我也有一个苹果充电线的接口
public interface IPhoneWire {
void charge();
}
苹果充电线接口的实现
public class IPhoneWireImpl implements IPhoneWire{
@Override
public void charge() {
System.out.println("我是苹果充电线的实现,可以给苹果手机充电哟~");
}
}
苹果手机使用充电线
public class IPhone {
public static void main(String[] args) {
IPhoneWire wire = new IPhoneWireImpl();
wire.charge();
}
}
结果
我是苹果充电线的实现,可以给苹果手机充电哟~
2.4 苹果手机用安卓线(使用适配器模式)
现在问题就是,我的苹果手机要用安卓的线,很明显直接来是不行的,得通过一个适配器,而适配器要让苹果手机用,就得实现苹果手机充电线的接口,而且功能还得让安卓充电线来完成,于是乎就有了下面这个类。
适配器类,有一个安卓充电线字段,通过构造方法设置这个字段,让这个字段来实现充电功能。
public class Adapter implements IPhoneWire{
//安卓充电线
private AndroidWire wire;
public Adapter(AndroidWire Wire){
this.wire = Wire;
}
@Override
public void charge() {
wire.charge();
System.out.println("但是我可以给IPhone充电咯,因为人家有适配器~");
}
}
苹果手机使用安卓充电线,这个时候我的苹果类就需要改动一下了
public class IPhone {
public static void main(String[] args) {
//安卓充电线
AndroidWire androidWire = new AndroidWireImpl();
//通过构造方法传给适配器
IPhoneWire wire = new Adapter(androidWire);
//充电
wire.charge();
}
}
结果
我是安卓充电线的实现,可 以给安卓手机充电哟~
但是我可以给IPhone充电咯,因为人家有适配器~
看,这样子就实现了用安卓充电线给苹果手机充电的功能。
整个结构图如下,有没有发现跟适配器模式的结构图对应上了
2.5 双向适配器
那么问题又来了,如果我想用苹果的充电线给安卓手机用怎么办?还是再来一个转换口?那我又想就用一个转换口,就能让安卓手机使用苹果充电线,用苹果手机使用安卓充电线呢(虽然看起来有点闲的蛋疼)?当然了,这个转换口在现实中还不存在,假设存在的话,这个东西其实就是一个双向适配器了。代码我就不贴了,可能适配器的方法要变一下,然后实现两个充电线接口,然后再将这两个充电线接口的实现类对象传进来,然后分别用这两个对象的方法实现功能,下面是这个结构图
3. 类适配器模式
其实在标准的适配器模式中,适配器的实现有以下两种
- 对象适配器
- 类适配器
而我们上面用到的就是对象适配器。
上面我们的适配器是用传进来的对象来完成功能的,而类适配器的话, 便不会用传进来的对象实现功能,而是直接继承该对象的类,这样子的话,这个适配器也有该类的方法,也可以实现功能了。如上面的例子,适配器类就可以改成下面这样子。
public class Adapter extends AndroidWireImpl implements IPhoneWire{
public void charge() {
//调用父类的充电方法
super.charge();
System.out.println("但是我可以给IPhone充电咯,因为人家有适配器~");
}
}
使用该适配器
public class IPhone {
public static void main(String[] args) {
IPhoneWire wire = new Adapter();
wire.charge();
}
}
整个结构图就变成下面这个样子了
4. 结言
下面补充两点
- 其实一个适配器可以适配多个类,比如说对象适配器的话,就可以传入多个被适配类的对象,但是由于Java不能多继承,所以类适配器要适配多个类的话不是很靠谱。
- 不能滥用适配器,由上面的例子我们可以看到,我们调用的是苹果的充电线接口,但是具体实现的却是安卓充电线,一个系统如果出现了太多这种情况,无疑是一种灾难。所以,如果可以的话,尽量不要使用适配器,而是直接重构。
简单一句话描述适配器模式
转换匹配,复用功能
如果上面的内容有错误的地方或者讲的不好的地方,还请大家指点一下,我好及时修改。