一、适配器模式是什么?
适配器模式又称变压器模式,主要功能就是将一个类的接口变成客户端所期望的另一种接口,从而使得原本因为接口不匹配无法在一起工作的两个类因为适配器类的存在而能够一起工作。适配器类起到了转化/委托的作用。
关于适配器模式的最好阐述例子如下:
我们都知道中国的家用电压是220V,日本的家用电压是110V,原则上在中国买的手机直接使用220V的充电器就可以在中国进行充电了,日本也是一样。阐述这一事实的代码如下:
public interface CnPluginInterface {
public void chargeWith220V(String phoneName);
}
public interface JpPluginInterface {
public void chargeWith110V(String phoneName);
}
public class CnPlugin implements CnPluginInterface {
@Override
public void chargeWith220V(String phoneName) {
System.out.println(phoneName + " is charging with 220V");
}
}
public class JpPlugin implements JpPluginInterface {
@Override
public void chargeWith110V(String phoneName) {
System.out.println(phoneName + " is charging with 110V");
}
}
public class ChinesePhone {
private String phoneName;
private CnPluginInterface cnPlugin;
public ChinesePhone(String phoneName,CnPluginInterface cnPlugin){
this.phoneName = phoneName;
this.cnPlugin = cnPlugin;
}
public void charge(){
cnPlugin.chargeWith220V(phoneName);
}
}
public class JapanesePhone {
private String phoneName;
private JpPluginInterface jpPlugin;
public JapanesePhone(String phoneName,JpPluginInterface jpPlugin){
this.phoneName = phoneName;
this.jpPlugin = jpPlugin;
}
public void charge(){
jpPlugin.chargeWith110V(phoneName);
}
}
CnPluginInterface cnPlugin = new CnPlugin();
ChinesePhone huawei = new ChinesePhone("huawei",cnPlugin);
huawei.charge();
JpPluginInterface jpPlugin = new JpPlugin();
JapanesePhone sony = new JapanesePhone("sony",jpPlugin);
sony.charge();
如上代码分别实例化了一个中国手机和一个日本手机,它们使用各自的充电器在自己国家内充电,一切正常。
然而如果将中国的手机带到日本去了,将日本的手机带到中国来了,那怎么充电呢?
我们分别需要一个电压转换器,这个转换器就是一个适配器,比如中国的手机到了日本,那么需要一个可以将110V电压转换为220V电压的适配器,从而可以让中国手机正常充电。同样的,日本手机来到中国,也需要一个可以将220V电压转换为110V电压的适配器。
我们的手机和充电器都是已经生产好了的,所以不需要修改,只需要增加适配器即可。
public class CnToJpAdapter implements CnPluginInterface {
private JpPluginInterface jpPlugin;
public CnToJpAdapter(JpPluginInterface jpPlugin){
this.jpPlugin = jpPlugin;
}
@Override
public void chargeWith220V(String phoneName) {
jpPlugin.chargeWith110V(phoneName);
}
}
如上就是一个可以将110V电压转换为220V电压的适配器,我们来看看它都做了什么?
- 实现了中国境内通用充电器的接口;
- 内部组合了一个日本境内通用充电器;
- 当组装该适配器的时候,将日本境内通用充电器填充进来;
- 当使用该适配器的时候,其内部实际使用的是日本的110V充电器,然后将日本境内通用充电器接受到的110V电压转换为220V的电压输出。
同样的,我们再来生产一个将220V电压转换为110V电压的适配器:
public class JpToCnAdapter implements JpPluginInterface {
private CnPluginInterface cnPlugin;
public JpToCnAdapter(CnPluginInterface cnPlugin){
this.cnPlugin = cnPlugin;
}
@Override
public void chargeWith110V(String phoneName) {
cnPlugin.chargeWith220V(phoneName);
}
}
有了适配器,我们给手机充电的方式就改为:
public class Test {
public static void main(String[] args) {
JpPluginInterface jpPlugin = new JpPlugin();
CnToJpAdapter cja = new CnToJpAdapter(jpPlugin);
ChinesePhone huawei = new ChinesePhone("huawei",cja);
huawei.charge();
CnPluginInterface cnPlugin = new CnPlugin();
JpToCnAdapter jca = new JpToCnAdapter(cnPlugin);
JapanesePhone sony = new JapanesePhone("sony",jca);
sony.charge();
}
}
对比两次充电方式,我们可以看出:
- 对于手机而言,它们直接面对的充电器(或者是使用适配器包装过的充电器)都是提供的和它匹配的充电电压,比如中国手机到了日本实际充电电压为220V。
- 对于充电器而言,它们接入的仍然都是自己能正常工作的电压环境,比如日本充电器接入的是110V的电网。
- 唯一的区别是,进入日本的中国手机摒弃了原来的中国充电器,而是选择重新购买一个由日本充电器和110V转220V电压的适配器所组成的中国手机在日本专用的充电器,这里就是
CnToJpAdapter
。
二、为什么要使用适配器模式?
当你想使用一个已有的类,但是这个类的接口跟你预想的需要的又不一样,不能拿来直接用,这个时候你就需要一个适配器来帮你了,其主要作用就是在旧的接口、新的接口之间完成适配。可以认为是已有系统进行增量需求开发时用的一种手段。
三、如何使用适配器模式?
- 适配器必须实现原有的旧的接口,主要是为了实现其中旧的实现方法;
- 适配器必须组合一个新接口的对象,在实现旧接口的方法时,偷天换日,改为使用新接口对象去实现;
四、实际使用案例
- Spring中的AdvisorAdapter类
- Spring中的HandlerAdapter类
五、模式总结
5.1 优点
- 提高了类的透明性和复用性,用户端无需知道是如何使用旧的类的;
- 客户端通过适配器类和原有的类进行了解耦,提高了程序的可扩展性;
- 符合开闭原则
5.2 缺点
- 增加了系统的复杂性;
- 增加了代码阅读难度,过多地使用适配器会使代码凌乱难以理解;