适配器模式基本介绍
介绍一个生活中的常例子:
你去日本旅游,发现自己的手机并不能在日本供电插座上充电,这是国家采用的用电标准不一致的问题而导致的。
例如:一些常见国家的使用电压:
使用110V:日本、韩国、菲律宾、法国、俄罗斯、西班牙、加拿大、墨西哥、美国等。
使用220V:印尼、印度、马来西亚、新加坡、泰国、土耳其、越南、奥地利、比利时、保加利亚、白俄罗斯、捷克、俄罗斯、丹麦、芬兰、德国、希腊、匈牙利、冰岛、爱尔兰、意大利、荷兰、挪威、波兰、葡萄牙、罗马尼亚、巴西、瑞典、新西兰、澳大利亚等。
在上下两类中的国家由于采用用电标准不一致,个人需要使用转换器(converter)来转换成自己的电子产品所采用的用电标准。
在这里起作用的转换器也可以称为适配器(adapter),基于这种生活场景,我们来介绍一下适配器模式:
适配器模式是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
主要有三类:类适配器模式、对象适配器模式、接口适配器模式。
一、类适配器
UML类图如下:
从上到下开始:
定义一个目标类的接口:
//目标类,作为接口
public interface ITargetVoltage {
public void outPut220();
}
这里是具体目标类,假设为中国等国家的220V插座:
//具体目标类
public class ConcreteTargetVoltage implements ITargetVoltage {
@Override
public void outPut220() {
System.out.println("220V插座");
}
}
被适配类,注意是"被",为了方便说明,这里假设为日本等国家的110V电压插座:
//被适配类
public class AdapteeVoltage {
public void outPut110(){
System.out.print("110V插座");
}
}
适配器类,在这个适配器类中,我们需要完成从被适配类到目标类的一系列转换操作,这里简单写为字符串输出代表已经经过操作
//适配器
public class Adapter extends AdapteeVoltage implements ITargetVoltage {
@Override
public void outPut220() {
//调用父类(被适配器类方法),在这里理解为拿到110V插座
super.outPut110();
//进行转换
System.out.print("->进入适配器内部转换->");
//得到输出
System.out.print("输出220V");
}
}
客户端调用:
public class Client {
public static void main(String[] args) {
//先拿个国内220V插座(目标类)验证一下
ITargetVoltage iVoltage220 = new ConcreteTargetVoltage();
iVoltage220.outPut220();
//通过适配器(集成了被适配类在里面)
//按当前例子来说就是转换器和插座已经放在一起了
ITargetVoltage iTargetVoltage = new Adapter();
iTargetVoltage.outPut220();
}
}
输出结果:
220V插座
110V插座->进入适配器内部转换->输出220V
客户端分别调用了目标类的具体实现类(这里表现为220V插座)和适配器类(这里表现为继承110V插座外加上实现220V插座的功能),通过调用其目标类接口的重写方法,返回了需要得到的目标类的结果(220V电压),于是我们的任何产品都可以通过这个适配器使用了。
二、对象适配器
这种方式与上述基本相同,只是关联方式变成了聚合,即在适配器类里声明被适配类作为其属性存在,并且通过构造器给与初始化:
//适配器
public class Adapter implements ITargetVoltage {
//关联关系——聚合
private AdapteeVoltage adapteeVoltage;
public Adapter(AdapteeVoltage adapteeVoltage) {
this.adapteeVoltage = adapteeVoltage;
}
@Override
public void outPut220() {
adapteeVoltage.outPut110();
System.out.print("->进入适配器内部转换->");
System.out.print("输出220V");
}
}
相应的客户端的调用需要稍微改变:
public class Client {
public static void main(String[] args) {
ITargetVoltage iVoltage220 = new ConcreteTargetVoltage();
iVoltage220.outPut220();
//在适配器类里传入被适配类的对象
ITargetVoltage iTargetVoltage = new Adapter(new AdapteeVoltage());
iTargetVoltage.outPut220();
}
}
三、接口适配器
这里假设一个场景,相信大家都见过万能充电接口,就是一条主充电线中分出来三种充电线分别为:Micro-USB、Type-C、Lightning,对应安卓、Type-C、苹果接口,就是一种多功能充电线。
同样,假如目标类可以有多种情况:
public interface MultiTarget {
public void Micro_USB();
public void TypeC();
public void Lightning();
}
抽象实现类,不提供具体的实现方法:
public abstract class AbstractAdapter implements MultiTarget{
@Override
public void Micro_USB() {
}
@Override
public void TypeC() {
}
@Override
public void Lightning() {
}
}
在实例化适配器的时候可以自定义想要的适配器:
public class Client {
public static void main(String[] args) {
//自定义适配器
AbstractAdapter abstractAdapter = new AbstractAdapter(){
@Override
public void Micro_USB() {
System.out.println("安卓充电接口");
}
};
}
}
总结
①三种命名方式,是根据 目标是以怎样的形式给到Adapter(在Adapter里的形式)来命名的。
②
类适配器:以类给到,在Adapter里,就是将src当做类,继承;
对象适配器:以对象给到,在Adapter里,将src作为一个对象属性;
接口适配器:以接口给到,在Adapter里,将src作为一个接口,实现。