一、什么是适配器模式?
适配器模式是一种结构型设计模式,它允许将不兼容的对象转换成可兼容的接口。主要目的是解决在不改变现有代码的情况下,使不兼容的接口之间能够正常工作,通过创建一个中间转换的适配器来将一个对象转换成我们所需要的接口。
大白话: 适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者。简单理解就是转换器、转接口的存在。
举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
二、适配器模式角色划分
- 目标接口(Target): 需要适配的标准接口,是当前业务中所期待的接口,它可以是抽象类或者接口。
- 被适配者(Adaptee): 需要被适配的不兼容对象。
- 适配器对象(adapter): 当中间转换角色,该对象将被适配者转换成目标接口。
三、应用场景
生活场景
- 电压转换器:不同国家的电压规格各异,同样功率的电器在不同的地方工作时需要不同的电压,电压转换器作为适配器,将不同电压转换成电器使用标准电压。
- 耳机转接头:有些手机没有耳机插口,需要使用转接头适配器,将耳机转换为手机支持的接口,实现对不同的耳机兼容。
Java场景
- JDBC驱动程序:不同的数据库提供商实现了不同的JDBC驱动接口,使用适配器模式可以将这些不同的接口适配为标准的JDBC接口,提高应用程序的可移植性。
- 日志框架:Java中有多个常用的日志框架,如Log4j、SLF4J等,不同的日志框架提供的API不同,使用适配器模式可以将这些不同的API适配为一个统一的接口,方便再程序中进行日志记录和管理。
- 第三方库或SDK:在使用第三方库或 SDK 时,可能由于它们实现的 API 不同而导致应用程序复杂,使用适配器模式可以将不同的 API 适配为统一的接口,简化应用程序的调用。
四、代码实现
类适配器模式
顾名思义,适配器通过类来实现,以类来继承和实现接口的方式,来获取被适配类的信息并转换输出重写到适配接口。
案例 1 (苹果手机接口适配安卓)
// 安卓手机接口
public interface AndroidInterface {
// typeC接口耳机
void androidHeadSet();
// ..... 其他接口
}
// 安卓手机实现类
public class AndroidHeadSet implements AndroidInterface {
@Override
public void androidHeadSet() {
System.out.println("这里是使用安卓耳机接口的连接");
}
}
// iphone苹果手机接口
public interface IPhoneInterface {
// lightning接口耳机
void iphoneHeadSet();
}
// 苹果手机实现类
public class IPhoneHeadSet implements IPhoneInterface{
@Override
public void iphoneHeadSet() {
System.out.println("这里是使用lightning接口耳机的连接");
}
}
// 注意接下来!!!
// 适配器类
public class HeadSetAdapter extends AndroidHeadSet implements IPhoneInterface {
// 重写iphone耳机方法 并调用父类安卓耳机的方法,已达到适配器模式的目的
// 解决接口不兼容不能在一起工作的问题
@Override
public void iphoneHeadSet() {
super.androidHeadSet();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 直接通过苹果接口 使用苹果耳机
IPhoneInterface iPhoneInterface = new IPhoneHeadSet();
iPhoneInterface.iphoneHeadSet();
//通过类的适配器进行连接
HeadSetAdapter headSetAdapter = new HeadSetAdapter();
headSetAdapter.iphoneHeadSet();
}
}
这里HeadSetAdapter耳机适配器类,为什么会 继承 AndroidHeadSet 实现 IPhoneInterface ?
- 通过继承 AndroidHeadSet ,适配器类获得了androidHeadSet()方法
- 通过实现IPhoneInterface接口,在重写的iphoneHeadSet()方法中调用androidHeadSet()方法
- 适配器类能够将IPhoneInterface接口的调用转发给AndroidHeadSet类的实现 androidHeadSet() 方法
案例 2(将 220v 电压转化为 5v 可以使用的)
//被适配的类
public class Voltage220V {
public int output220V() {
int src = 220;
System.out.println("电压=" + src);
return src;
}
}
//适配接口
public interface IVoltage5V {
public int output5V();
}
//适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
// TODO Auto-generated method stub
//获取220V电压
int srcV = output220V();
int dstV = srcV / 44 ; //转成5v
return dstV;
}
}
//调用
public class Phone {
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压是5v,可以充电");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("电压大于5v,不可充电");
}
}
}
//测试
public class Client {
public static void main(String[] args) {
System.out.println("===类适配器测试===");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
}
}
对象适配器
顾名思义,通过实例对象(构造器传递)来实现适配器,而不是再用继承,其余基本同类适配器。
案例 1(苹果手机接口适配安卓)
// 安卓手机接口
public interface AndroidInterface {
// typeC接口耳机
void androidHeadSet();
// ..... 其他接口
}
// 安卓手机实现类
public class AndroidHeadSet implements AndroidInterface {
@Override
public void androidHeadSet() {
System.out.println("这里是使用安卓耳机接口的连接");
}
}
// iphone苹果手机接口
public interface IPhoneInterface {
// lightning接口耳机
void iphoneHeadSet();
}
// 苹果手机实现类
public class IPhoneHeadSet implements IPhoneInterface{
@Override
public void iphoneHeadSet() {
System.out.println("这里是使用lightning接口耳机的连接");
}
}
// 注意接下来!!!
// 适配器类
public class ObjectHeadSetAdapter implements IPhoneInterface {
private AndroidInterface androidInterface;
public ObjectHeadSetAdapter(AndroidInterface androidInterface) {
this.androidInterface = androidInterface;
}
@Override
public void iphoneHeadSet() {
androidInterface.androidHeadSet();
}
}
public class Client {
public static void main(String[] args) {
// 直接通过苹果接口 使用苹果耳机
IPhoneInterface iPhoneInterface = new IPhoneHeadSet();
iPhoneInterface.iphoneHeadSet();
//通过类的适配器进行连接
HeadSetAdapter headSetAdapter = new HeadSetAdapter();
headSetAdapter.iphoneHeadSet();
//通过对象的适配器进行连接
AndroidInterface androidInterface = new AndroidHeadSet();
ObjectHeadSetAdapter objectHeadSetAdapter = new ObjectHeadSetAdapter(androidInterface);
objectHeadSetAdapter.iphoneHeadSet();
}
}
案例 2(将 220v 电压转化为 5v 可以使用的)
//被适配的类(不变)
public class Voltage220V {
public int output220V() {
int src = 220;
System.out.println("电压=" + src);
return src;
}
}
//适配接口(不变)
public interface IVoltage5V {
public int output5V();
}
//适配器类
public class VoltageAdapter implements IVoltage5V {
private Voltage220V voltage220V;
//构造器
public VoltageAdapter(Voltage220V voltage220v) {
this.voltage220V = voltage220v;
}
@Override
public int output5V() {
int dst = 0;
if(null != voltage220V) {
int src = voltage220V.output220V();//获取220v电压
dst = src / 44;
}
return dst;
}
}
//调用(不变)
public class Phone {
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压是5v,可以充电");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("电压大于5v,不可充电");
}
}
}
//测试
public class Client {
public static void main(String[] args) {
System.out.println("===对象适配器===");
Phone phone = new Phone();
VoltageAdapter VoltageAdapter = new VoltageAdapter(new Voltage220V());
phone.charging(VoltageAdapter);
}
}
接口适配器
接口适配器也称缺省适配器模式,适用于一个接口不想使用其所有的方法的情况。当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
案例 1
//被适配的类(不变)
public class Voltage220V {
public int output220V() {
int src = 220;
System.out.println("电压=" + src);
return src;
}
}
//适配接口
public interface IVoltage5V {
public int output5V();
public void m2(); //接口里冗余不重要的方法
public String m3();
}
//抽象适配器
public abstract class AbsAdapter extends Voltage220V implements IVoltage5V{
@Override //以空方法实现接口所有方法
public int output5V() {
return 0;
}
@Override
public void m2() {
}
@Override
public String m3() {
return null;
}
}
//调用(不变)
public class Phone {
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压是5v,可以充电");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("电压大于5v,不可充电");
}
}
}
//测试
public class Client {
public static void main(String[] args) {
System.out.println("===接口适配器===");
AbsAdapter absAdapter = new AbsAdapter() { //匿名内部类的形式
@Override //按需要重写接口方法
public int output5V() {
System.out.println("使用了output5V的方法");
int srcV = output220V();
int dstV = srcV / 44 ; //转成5v
return dstV;
}
};
Phone phone = new Phone();
phone.charging(absAdapter);
}
}