目录
一、什么是适配器模式
二、角色组成
三、优缺点
四、应用场景
4.1 生活场景
4.2 java场景
五、代码实现
5.0 代码结构
5.1 类适配器模式
5.2 对象适配器模式
5.3 接口适配器模式
六、总结
适配器模式是一种结构型设计模式,它允许将不兼容的对象转换成可兼容的接口。主要目的是解决在不改变现有代码的情况下,使不兼容的接口之间能够正常工作,通过创建一个中间转换的适配器来将一个对象转换成我们所需要的接口。
- 目标接口(target):需要适配的标准接口。
- 源对象(source):需要被适配的不兼容对象。
- 适配器对象(adapter):充当中间转换角色,该对象将源对象转换成目标接口。
优点:
- 安全可靠:封装了旧接口,对客户端透明,客户端代码无需修改。
- 提高复用性:可以复用不兼容的类;可以对不同的类无需修改,就可以进行组合。
- 扩展性好:在应用程序开发过程中,可以增加新的适配器和被适配对象。
缺点:
- 过多的适配器会导致系统结构复杂。
- 如果适配器没有实现好,可能会拖慢整个系统的性能。
- 滥用适配器模式会导致系统设计紊乱。
- 电压转换器:不同国家的电压规格各异,同样功率的电器在不同的地方工作时需要不同的电压,电压转换器作为适配器,将不同电压转换成电器使用标准电压。
- 耳机转接头:有些手机没有耳机插口,需要使用转接头适配器,将耳机转换为手机支持的接口,实现对不同的耳机兼容。
- JDBC驱动程序:不同的数据库提供商实现了不同的JDBC驱动接口,使用适配器模式可以将这些不同的接口适配为标准的JDBC接口,提高应用程序的可移植性。
- 日志框架:Java中有多个常用的日志框架,如Log4j、SLF4J等,不同的日志框架提供的API不同,使用适配器模式可以将这些不同的API适配为一个统一的接口,方便再程序中进行日志记录和管理。
- 第三方库或SDK:在使用第三方库或 SDK 时,可能由于它们实现的 API 不同而导致应用程序复杂,使用适配器模式可以将不同的 API 适配为统一的接口,简化应用程序的调用。
当我们去国外旅游时,我们可能只会汉语,而当地人只会英语,那么这个时候就需要一个翻译员(翻译软件)来帮助我们。这就类似于适配器模式,通过一个适配器将一个不兼容的接口转成另外一个接口。下面以翻译为例,介绍一下类、接口、对象适配器。
使用继承的方式,将需要适配的类转换为目标接口的子类,实现目标接口的所有方法,同时继承适配类的实现,用以完成一些适配逻辑。
目标接口‘target’,里面定义了一个‘translate’方法。(对象适配器模式也要用)
/**
* @author Created by njy on 2023/6/8
* 目标接口(target)
*/
public interface Target {
/**
* 翻译
* @param source 母语
* @param target 要翻译成的语种
* @param words 内容
*/
void translate(String source,String target,String words);
}
翻译类‘Translator’ ,里面有‘TranslateInZh’和‘TranslateInEn’方法。(对象、接口适配器模式也要用)
/**
* @author Created by njy on 2023/6/8
* 源对象(source):充当翻译
*/
public class Translator {
//英——》汉
public void translateInZh(String words){
if("hello world!".equals(words)){
System.out.println("翻译成中文:”你好世界!“");
}
}
//汉——》英
public void translateInEn(String words){
if("你好世界!".equals(words)){
System.out.println("Translate in English:”hello world!“");
}
}
}
ClassAdapter
/**
* @author Created by njy on 2023/6/11
* 类适配器:通过多重继承目标接口和被适配者类方式来实现适配
*/
public class ClassAdapter extends Translator implements Target {
@Override
public void translate(String source, String target, String words) {
if("中文".equals(source) && "英文".equals(target)) {
//汉--》英
this.translateInEn(words);
} else {
//英--》汉
this.translateInZh(words);
}
}
}
testClassAdapter
/**
* @author Created by njy on 2023/6/8
*/
@SpringBootTest
public class TestAdapter {
//类适配器
@Test
void classAdapter(){
//创建一个类适配器对象
ClassAdapter adapter=new ClassAdapter();
adapter.translate("中文", "英文", "你好世界!");
adapter.translate("英语","中文","hello world!");
}
}
通过组合的方式,将适配对象与目标接口组合,实现目标接口的所有方法,并在适配类中调用需要适配对象的方法。
ObjectAdapter
/**
* @author Created by njy on 2023/6/11
* 对象适配器:使用组合的方式
*/
public class ObjectAdapter implements Target {
private Translator translator=new Translator();
@Override
public void translate(String source, String target, String words) {
if("中文".equals(source) && "英文".equals(target)) {
//汉--》英
translator.translateInEn(words);
} else {
//英--》汉
translator.translateInZh(words);
}
}
}
testObjectAdapter
/**
* @author Created by njy on 2023/6/8
*/
@SpringBootTest
public class TestAdapter {
//对象适配器
@Test
void ObjectAdapter(){
ObjectAdapter adapter=new ObjectAdapter();
adapter.translate("中文", "英文", "你好世界!");
adapter.translate("英语","中文","hello world!");
}
}
主要适用于需要被适配的接口中,只有用到个别接口,也就是说不需要实现它的全部接口。通过一个中间抽象类或接口实现。
target2:用于解释接口适配器
/**
* @author Created by njy on 2023/6/11
* target2:用于解释接口适配器
*/
public interface target2 {
/**
* 翻译
* @param source 母语
* @param target 要翻译成的语种
* @param words 内容
*/
void translate(String source,String target,String words);
//无用方法,仅仅用来说明接口适配器
void a();
}
AbstractAdapter抽象类
/**
* @author Created by njy on 2023/6/8
* AdapterTranslate抽象类
*/
public abstract class AbstractAdapter implements target2 {
private Translator translator=new Translator();
@Override
public void translate(String source, String target, String words) {
if("中文".equals(source) && "英文".equals(target)) {
//汉--》英
translator.translateInEn(words);
} else {
//英--》汉
translator.translateInZh(words);
}
}
@Override
public void a() {
}
}
InterfaceAdapter:接口适配器
/**
* @author Created by njy on 2023/6/11
* 接口适配器:当不需要全部实现接口方法时。
* 可以先设计一个抽象类实现接口AdapterTranslate
* AdapterTranslate实现,不用去实现b()方法
*/
public class InterfaceAdapter extends AbstractAdapter {
public void translate(String source, String target, String words) {
super.translate(source,target,words);
}
}
testInterfaceAdapter
/**
* @author Created by njy on 2023/6/8
*/
@SpringBootTest
public class TestAdapter {
//接口适配器
@Test
void interfaceAdapter(){
InterfaceAdapter adapter=new InterfaceAdapter();
adapter.translate("中文", "英文", "你好世界!");
adapter.translate("英语","中文","hello world!");
}
}
适配器模式的适用场景:
- 重用现有的代码:适配器模式可以允许我们重用已有的类或接口,而不需要修改其原有的代码。
- 集成老系统:当现有的系统不满足用户需求时,需要增加系统功能或接口。但是,老系统的接口可能与现有的技术、平台不兼容,此时可以采用适配器模式,将现有的接口适配为新的接口,从而实现新系统的集成。
- 集成第三方组件:在使用第三方组件时,可能由于它们实现的 API 不同而导致应用程序复杂,此时可以使用适配器模式,将第三方组件提供的 API 适配为自己需要的 API,方便在应用程序中进行调用。
- 实现跨平台兼容:在不同平台、不同技术栈之间进行开发时,常常需要适配不同的接口,以使得不同的平台或技术栈之间能够相互兼容,此时可以使用适配器模式来处理各种不兼容问题。