一、前言
适配器在生活中非常常见。比如去香港玩,香港是英式三孔插座,为了能兼容大陆版的手机充电器,需要买个适配器,适配器本身是英式三孔插头,对外提供一个大陆版两孔插座,这样就可以使用大陆版两孔插头,在香港英式三孔插座充电了。
二、什么是适配器模式
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使不兼容的两个接口协同工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
根据适配器类和适配者类的关系不同,适配器模式可以分为对象适配器和类适配器。
1、对象适配器模式:适配器和适配者之间是关联关系(使用组合);
2、类适配器模式:适配器和适配者之间是继承(实现)关系(使用继承);
注意:很多文献,对适配器模式的划分,又新增了接口适配器模式,又称之为缺省适配器模式。
3、缺省适配器模式(Default Adapter Pattern):当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性的覆盖父类的某些方法来实现需求。它适用于不想使用一个接口中所有方法的情况。
三、为什么要使用适配器模式
1、系统需要使用现有的类,而这些类的接口不符合系统的需要;
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的类一起工作;
3、需要一个统一的输出接口,而输入端的类型不可预知;
四、适配器模式的结构
4.1、角色说明
Target(目标抽象类):目标接口,该角色把其他接口转换为我们期待的接口;
Adaptee(适配者类):被适配的接口,原有存在的接口,也是被希望改变的接口;
Adapter(适配器类):将被适配的接口和目标接口组合到一起的类;
五、代码示例
此处以充电器的例子来讲解适配器,充电器是Adapter,220V交流电是Adaptee,5V直流电是Target。
5.1、类适配器模式
类适配器主要是使用继承的方式连接目标接口和被适配的接口。
5.1.1、Target 目标接口(5V直流电)
public interface Voltage5V {
int out5V();
}
5.1.2、Adaptee适配者类(220V交流电)
public class Voltage220V {
public int out220V(){
int src = 220;
System.out.println("我是交流电" + src + "V");
return src;
}
}
5.1.3、Adapter适配器类
public class VoltageAdapter extends Voltage220V implements Voltage5V {
@Override
public int out5V(){
int src = out220V();
System.out.println("适配器工作开始适配电压");
int dst = src / 44;
System.out.println("适配完成后输出电压:" + dst + "V");
return dst;
}
}
5.1.4、Client客户端
public class Client {
public int change(Voltage5V voltage5V){
int src = voltage5V.out5V();
System.out.println("电压已转换为:" + src + "V");
}
}
5.2、对象适配器模式(常用)
对象适配器主要是使用组合的方式连接目标接口和被适配的接口。
5.2.1、Target 目标接口(5V直流电)
public interface Voltage5V {
int out5V();
}
5.2.2、Adaptee适配者类(220V交流电)
public class Voltage220V {
public int out220V(){
int src = 220;
System.out.println("我是交流电" + src + "V");
return src;
}
}
5.2.3、Adapter适配器类
public class VoltageAdapter implements Voltage5V {
private Voltage220V voltage220V ;
public VoltageAdapter (Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int out5V(){
int src = voltage220V.out220V();
System.out.println("适配器工作开始适配电压");
int dst = src / 44;
System.out.println("适配完成后输出电压:" + dst + "V");
return dst;
}
}
5.2.4、Client客户端
public class Client {
public int change(Voltage5V voltage5V){
int src = voltage5V.out5V();
System.out.println("电压已转换为:" + src + "V");
}
}
六、类适配器模式和对象适配器模式的对比
6.1、类适配器的缺点
通过类适配器模式代码示例,把220V 和 5V两个接口连接了起来,但实现编码场景下,类适配器模式用的比较少,因为Java不支持多继承,一次最多只能适配一个适配者类,使用不太灵活。同时Java中,尽量少用继承,多用组合。
6.1、对象适配器的优点
相比较类适配器模式,通过组合方式,一个对象适配器可以把多个不同的适配者适配到同一个目标,使用更加灵活多样,推荐使用。