微信公众号搜索:程序驴,查看更多学习笔记
何为适配器模式
举一个很贴切的例子,我们国家的家用交流电,电压是220V的,但是在美国,他们的家用电压为110V,因此如果我们要想在国外也能达到国内一样的充电体验,我们可能需要购买一个适配器,来将110V电压转换为220V。
这个例子中适配器的作用就是将现有的条件(110V)做出转化(适配器),使其符合我们的需要(220V)
其实适配器模式更贴近实际的用法是把多种有差别(但功能差不多)的接口做统一化的输出,这样不管是之后向更改接口还是切换服务提供者,都不会影响到接口使用方的业务逻辑。
再举个小例子,适配器模式其实就像是一个只注重结果的人,利用适配器,他不在乎你怎么提供的,他只在乎你提供给他的结果是否和之前的一样。只要结果一致,那你作为提供者可以随便捣鼓。
实战案例
在建站过程中,OSS服务是必不可少的一环,他可以作为图床,存放我们网站的图片资源,并返回图片的访问url,但是市面上有很多的OSS服务提供者,比如需要money的阿里云,腾讯云之类的,也有可以自己手搭的Minio,这些OSS服务提供的功能接口一致,但是接口的方法名,参数类型多有不同,如果在开发过程中更换服务提供者,那可就是牵一发而动全身,想象一下下面的场景:OSS服务接口一换,原本优雅的代码,突然error99+,不是方法找不到,就是参数缺一少一,实在是让人蛋疼。
因此,我们需要一个适配器,来统一管理这些接口提供的方法,让他们最终的“结果”一致,这样不管背后的服务发生了什么变化,只要你提供的接口不变,那我的适配器就能一直工作下去。下面是代码实现。
代码实现
目录结构:
Adapter
StorageAdapter:
public interface StorageAdapter {
/**
* @Description: 创建
*/
boolean create(String name);
/**
* @Description: 上传
*/
boolean upload(String bucket,String obj, byte[] data);
// ............
}
StorageAdapter作为统一的适配接口,它提供一些对于每个OSS服务都拥有的功能。
AliYunServiceAdapter:
public class AliYunServiceAdapter implements StorageAdapter{
private AliYunService aliYunService;
@Override
public boolean create(String name) {
return aliYunService.createByAlY(name);
}
@Override
public boolean upload(String bucket, String obj, byte[] data) {
return aliYunService.uploadByAlY(bucket,obj,data);
}
}
阿里云的适配器接口实现类,这里模拟引入了阿里云的接口,可以看做是利用阿里云提供的接口来实现适配器中的功能,达成"结果一致"。这里特意在方法后使用了"ByAlY",意为不同的服务提供者,所提供的方法可能会有不同。
MinioServiceAdapter:
/**
* @Author 林峰
* @Date 2024/4/15 0:03
* @Version 1.0
*
* Minio和适配器对接
*/
public class MinioServiceAdapter implements StorageAdapter{
private MinioService minioService;
@Override
public boolean create(String name) {
return minioService.createByMinio(name);
}
@Override
public boolean upload(String bucket, String obj, byte[] data) {
return minioService.uploadByMinio(bucket,obj,data);
}
}
Minio的适配器接口实现类
Config
StorageConfig:
public class StorageConfig {
static String type = "AliYun"; // 如果是spring,可以直接从配置文件注入
// static String type = "Minio";
private static StorageAdapter storageAdapter;
// 如果是spring,可以直接设置返回值作为Bean交由容器管理
public static StorageAdapter getStorageAdapter(){
if("AliYun".equals(type)){
storageAdapter = new AliYunServiceAdapter();
return storageAdapter;
}else if("Minio".equals(type)){
storageAdapter = new MinioServiceAdapter();
return storageAdapter;
}else{
throw new RuntimeException("未知的服务种类");
}
}
}
StorageConfig作为配置类,可以对全局的OSS服务做统一管理,可以靠其中的type实现服务自由的切换(适配器的优势),其中type可以在配置文件中进行配置,如果是微服务架构,也可以利用nacos实现远程配置,十分优雅。
这里还用到了单例设计模式,有机会再讲。
Main
/**
* @Author 林峰
* @Date 2024/4/14 23:13
* @Version 1.0
* 适配器设计模式
*/
public class AdapterMain {
public static void main(String[] args) {
// 获取适配器接口实现类
StorageAdapter storageAdapter = StorageConfig.getStorageAdapter();
// 调用
storageAdapter.create("林峰");
}
}
从main函数可以看出,因为我们用到的是StorageAdapter这个统一的适配器接口,而用到的哪个实例化,对于我们的业务都无所谓,这极大地提高了代码的可维护性,不会导致牵一发而动全身的情况发生。
总结
- 适配器模式多用在需要统一多个接口的输出,避免后期对接口服务的修改影响我们调用服务的业务代码
- 利用适配器模式可以更方便快捷地在多个服务间切换,也为我们扩展新的服务接口提供的方便
※ 以上知识点来源于个人的学习见解,如有错误,请私信联系:程序驴