1、概述
结构型模式
1. 适配器模式(Adapter Pattern)将某个类的接口转化为客户端期望的另一个接口表示,主要的目的是兼容性,让原本不匹配不能一起工作的两个类可以协同工作,其名为包装器(Wrapper)
2. 适配器模式属于结构型模式
3. 主要分为三类:类适配器模式、对象适配器模式、接口适配器模式
4. 工作原理就是:用户调用适配器转换出来的接口,适配器在调用被适配类的相关接口,从而完成适配
2、优缺点
优点:
安全可靠:封装了旧接口,对客户端透明,客户端代码无需修改。
提高复用性:可以复用不兼容的类;可以对不同的类无需修改,就可以进行组合。
扩展性好:在应用程序开发过程中,可以增加新的适配器和被适配对象。
缺点:
过多的适配器会导致系统结构复杂。
如果适配器没有实现好,可能会拖慢整个系统的性能。
滥用适配器模式会导致系统设计紊乱
3、实现方式
类适配器
//测试类
public class Test {
public static void main(String[] args) {
//类适配器使得代码逻辑混乱
//这种情况下仿佛Adapter是一种110V的美国供电器可以直接使用不需要其他信息
//具体可以和对象适配器对比以下
new Adapter().chargeBy220V();
}
}
//客户期望的接口——220V的电压充电
interface Target {
void chargeBy220V();
}
//现有接口——只能通过110V电压充电
interface Adaptee {
void chargeBy110V();
}
//现有接口的具体实现类,美国供电器——通过110V电压供电
class americanCharger implements Adaptee {
@Override
public void chargeBy110V() {
System.out.println("110V");
}
}
//类适配器,通过继承现有接口来完成对现有接口的扩展
class Adapter extends americanCharger implements Target {
@Override
public void chargeBy220V() {
super.chargeBy110V();//现有功能
System.out.println("220V");//对现有功能扩展
}
}
//输出
/*
110V
220V
*/
对象适配器
//测试类
public class Test {
public static void main(String[] args) {
//现在我们有一个美国110V供电站,但我们无法使用
Adaptee adaptee = new americanCharger();
//我们将这个供电器交给适配器,适配器转换为220V供电器
Adapter adapter = new Adapter(adaptee);
//接下来我们通过适配器充电就好了
adapter.chargeBy220V();
}
}
//客户期望的接口——220V的电压充电
interface Target {
void chargeBy220V();
}
//现有接口——只能通过110V电压充电
interface Adaptee {
void chargeBy110V();
}
//现有接口的具体实现类,美国供电器——通过110V电压供电
class americanCharger implements Adaptee {
@Override
public void chargeBy110V() {
System.out.println("110V");
}
}
//类适配器,通过继承现有接口来完成对现有接口的扩展,使得能够110V供电
class Adapter implements Target {
Adaptee adaptee;//持有现有接口具体实现对象的引用
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void chargeBy220V() {
adaptee.chargeBy110V();//该对象的现有功能
System.out.println("220V");//对现有功能扩展
}
}
接口适配器
//测试类
public class Test {
public static void main(String[] args) {
//现在我们有一个美国110V供电站,但我们无法使用
Adaptee adaptee = new americanCharger();
//我们将这个供电站交给中国制造的适配器
Adapter adapter = new ChinaMakeAdapter(adaptee);
//接下来我们通过适配器充电就好了
adapter.chargeBy220V();
}
}
//客户期望的接口——220V的电压充电
interface Target {
void chargeBy220V();
}
//现有接口——只能通过110V电压充电
interface Adaptee {
void chargeBy110V();
}
//现有接口的具体实现类,美国供电器——通过110V电压供电
class americanCharger implements Adaptee {
@Override
public void chargeBy110V() {
System.out.println("110V");
}
}
//抽象类适配器,通过继承现有接口来完成对现有接口的扩展
abstract class Adapter implements Target {
Adaptee adaptee;//持有现有接口具体实现对象的引用
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
}
//中国自制
class ChinaMakeAdapter extends Adapter {
public ChinaMakeAdapter(Adaptee adaptee) {
super(adaptee);
}
@Override
public void chargeBy220V() {
adaptee.chargeBy110V();//该对象的现有功能
System.out.println("220V");//对现有功能扩展
}
}
//测试类
public class Test {
public static void main(String[] args) {
//我们去美国,酒店里有一个美国110V充电站,我们需要220V的电压
B b = new AmericanCharger();
//我们将这个充电站交给适配器以获取220V电压充电
Adapter adapter1 = new Adapter(b);
//接下来我们通过适配器充电就好了
adapter1.chargeBy220V();
System.out.println();
//美国人来中国,酒店里有一个中国220V充电站,但他需要110V的电压
A a = new ChinaCharger();
//将这个充电站交给适配器以获取110V电压充电
Adapter adapter2 = new Adapter(a);
//接下来我们通过适配器充电就好了
adapter2.chargeBy110V();
}
}
//接口A——220V的电压供电
interface A {
void chargeBy220V();
}
//接口A的具体实现类,中国供电器——通过220V电压供电
class ChinaCharger implements A {
@Override
public void chargeBy220V() {
System.out.println("220V");
}
}
//接口B——110V电压供电
interface B {
void chargeBy110V();
}
//接口B的具体实现类,美国供电器——通过110V电压供电
class AmericanCharger implements B {
@Override
public void chargeBy110V() {
System.out.println("110V");
}
}
//双向适配器
class Adapter implements A, B {
A a; //220V充电
B b; //110V充电
public Adapter(A a) {
this.a = a;
}
public Adapter(B b) {
this.b = b;
}
@Override
public void chargeBy220V() {
b.chargeBy110V(); //当前接口
System.out.println("220V");//适配目标接口
}
@Override
public void chargeBy110V() {
a.chargeBy220V();//当前接口
System.out.println("110V");
}
}
/*
110V
220V
220V
110V
*/
4、应用场景
生活中
1. 电压转换器:不同国家的电压规格各异,同样功率的电器在不同的地方工作时需要不同的电压,电压转换器作为适配器,将不同电压转换成电器使用标准电压。
2. 耳机转接头:有些手机没有耳机插口,需要使用转接头适配器,将耳机转换为手机支持的接口,实现对不同的耳机兼容。
3. 显示器转接头,如VGA-HDMI;电脑数据线转接头,如typeC-usb
程序中
1. JDBC驱动程序:不同的数据库提供商实现了不同的JDBC驱动接口,使用适配器模式可以将这些不同的接口适配为标准的JDBC接口,提高应用程序的可移植性。
2. 日志框架:Java中有多个常用的日志框架,如Log4j、SLF4J等,不同的日志框架提供的API不同,使用适配器模式可以将这些不同的API适配为一个统一的接口,方便再程序中进行日志记录和管理。
3. 第三方库或SDK:在使用第三方库或 SDK 时,可能由于它们实现的 API 不同而导致应用程序复杂,使用适配器模式可以将不同的 API 适配为统一的接口,简化应用程序的调用。