结构型模式——适配器模式
(一)概述
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。例如,读卡器是作为内存卡和笔记本之间的适配器,我们将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
适配器模式一共有三个角色,从上面那个内存卡的例子也能看出来,主要分为:
1. 目标(Target)接口:当前系统业务所期待的接口,可以是抽象类或接口。
2. 适配者(Adaptee)类:被访问和适配的现存组件库中的组件接口。
3. 适配器(Adapter)类:一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
适配器模式非常简单,也很好理解。从代码实现的角度看,适配器模式又可以分为:类适配器模式、对象适配器模式。
下面是类适配器模式:
下面是对象适配器模式:
(二)类适配器模式
下面我们举一个手机充电器的例子来体会一下两种适配器模式。首先,电源输出为220V,充电器给手机充电的输出电压为5V,很显然,我们需要一个适配器来使得手机可以使用220V的电源充电。
首先我们先把电源写好:
public class Voltage220V {
public int output220V() {
int src = 220;
System.out.println("电源输出" + src + "V");
return src;
}
}
然后写好充电器的输出接口:
public interface Voltage5V {
int output5V();
}
适配器的作用就是将电源的220V降为可以给手机使用的5V:
public class VoltageAdapter extends Voltage220V implements Voltage5V {
@Override
public int output5V() {
int src = super.output220V();
int dst = src / 44;
System.out.println("转换为" + dst + "V");
return dst;
}
}
然后写手机,手机只能用5V充电,因此我们这里要使用适配器而不是直接使用220V电源:
public class Phone {
public static void charging(Voltage5V voltage5V){
int v = voltage5V.output5V();
if(v == 5){
System.out.println("接收电压为5V,正常充电");
}else if(v > 5){
System.out.println("电压高于5V,无法充电");
}
}
}
然后来测试一下:
public void test(){
Phone.charging(new VoltageAdapter());
}
我们可以发现类适配器模式的特点,适配器实现了目标接口同时也继承了适配者,这样适配器就同时具有了目标和适配者的特性,因此可以将两者进行转化。
(三)对象适配器模式
对象适配器和类适配器非常相似,只不过类适配器用的是继承而对象适配器用的是聚合而已,原理基本都是一样的。
还是上面那个例子,如果我们要把他修改成对象适配器模式,我们只需要修改一下适配器,将其改为聚合关系即可。
public class VoltageAdapter2 implements Voltage5V {
private Voltage220V voltage220V;
public VoltageAdapter2(){
this.voltage220V = new Voltage220V();
}
@Override
public int output5V() {
int src = this.voltage220V.output220V();
int dst = src / 44;
return dst;
}
}
测试一下:
public void test02(){
Phone.charging(new VoltageAdapter2(new Voltage220V()));
}
(四)适配器模式总结
通过这个例子我们可以总结适配器模式的一些优点:
1. 灵活性好
2. 可以让两个没有关系的类一起运行
3. 增加了类的通透性
那类适配器和对象适配器具体的使用场景有什么区别呢?首先我们大家都知道java不支持多继承,而我们的类适配器必须要继承适配者,这也就说明如果要将适配器和目标建立关系,目标必须是一个接口,这也就带来了很大的局限性。
因此,对象适配器的出现解决了这个问题。对象适配器没有使用继承关系而是选用了聚合关系,避免了多继承的问题。也就是说,对象适配器的使用范围更广。
2020年8月1日