介绍
在软件开发中,我们经常会遇到各种各样的类库和组件,它们可能拥有不同的接口设计,导致无法直接协同工作。这时,适配器模式(Adapter Pattern)就派上用场了。
适配器模式 就像一个翻译官,它将一个类的接口转换成另一个接口,让原本不兼容的类可以互相配合。
核心思想:
- 现有类(被适配者):已经存在,拥有我们想要的功能,但接口不符合我们的需求。
- 目标接口:定义了我们期望的接口,是我们想要使用的接口。
- 适配器:充当桥梁,将被适配者的接口转换为目标接口,让它们可以协同工作。
基础案例
你有一个手机充电器,它只能输出 5V 电压,而你的笔记本电脑需要 19V 电压才能正常工作。这时候,你需要一个适配器,将手机充电器的 5V 电压转换成 19V 电压,才能给笔记本电脑充电。
适配器模式 就如同这个转换器,它可以将一个接口(手机充电器)转换成另一个接口(笔记本电脑),让它们能够互相配合。
具体来说:
- 手机充电器 代表着现有的功能,但它的输出电压不符合笔记本电脑的需求。
- 笔记本电脑 代表着需要使用的设备,它需要 19V 电压才能正常工作。
- 适配器 则是一个转换器,它将手机充电器的 5V 电压转换成 19V 电压,让笔记本电脑能够使用手机充电器供电。
代码示例:
// 目标接口
interface LaptopCharger {
int output19V();
}
// 被适配者类
class PhoneCharger {
public int output5V() {
return 5;
}
}
// 适配器类
class ChargerAdapter implements LaptopCharger {
private PhoneCharger phoneCharger;
public ChargerAdapter(PhoneCharger phoneCharger) {
this.phoneCharger = phoneCharger;
}
@Override
public int output19V() {
int src = phoneCharger.output5V();
System.out.println("原始电压:" + src + "V");
int dst = src * 3.8; // 将 5V 电压转换成 19V 电压
System.out.println("转换后电压:" + dst + "V");
return dst;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
PhoneCharger phoneCharger = new PhoneCharger();
LaptopCharger adapter = new ChargerAdapter(phoneCharger);
int output19V = adapter.output19V();
System.out.println("输出电压:" + output19V + "V");
}
}
运行结果:
原始电压:5V
转换后电压:19V
输出电压:19V
看完这个例子,你已经对适配器模式有了不错的了解了。那么,如果我还想给台灯,显示器等电器充电呢,这个适配器又该如何设计?
进阶案例
新增了台灯,显示器
设计思路:
- 使用枚举类定义充电器类型,方便管理和维护。
- 使用接口定义充电器共有的方法,提高代码可扩展性。
- 使用适配器类将不同充电器类型的输出电压统一到一个方法中,简化客户端代码。
1. 定义接口:
interface Charger {
String getName();
int getVoltage();
}
2. 使用枚举类实现接口:
enum ChargerType implements Charger {
PHONE("手机充电器", 5),
LAPTOP("笔记本充电器", 19),
LAMP("台灯充电器", 12),
DISPLAY("显示器充电器", 24);
private String name;
private int voltage;
ChargerType(String name, int voltage) {
this.name = name;
this.voltage = voltage;
}
@Override
public String getName() {
return name;
}
@Override
public int getVoltage() {
return voltage;
}
}
3. 创建适配器类:
class ChargerAdapter {
private PhoneCharger phoneCharger = new PhoneCharger();
private LaptopCharger laptopCharger = new LaptopCharger();
private LampCharger lampCharger = new LampCharger();
private DisplayCharger displayCharger = new DisplayCharger();
public int getVoltage(ChargerType chargerType) {
switch (chargerType) {
case PHONE:
return phoneCharger.output5V();
case LAPTOP:
return laptopCharger.output19V();
case LAMP:
return lampCharger.output12V();
case DISPLAY:
return displayCharger.output24V();
default:
return 0;
}
}
}
4. 客户端代码:
public class Client {
public static void main(String[] args) {
ChargerAdapter adapter = new ChargerAdapter();
System.out.println(ChargerType.PHONE.getName() + " 电压:" + adapter.getVoltage(ChargerType.PHONE));
System.out.println(ChargerType.LAPTOP.getName() + " 电压:" + adapter.getVoltage(ChargerType.LAPTOP));
System.out.println(ChargerType.LAMP.getName() + " 电压:" + adapter.getVoltage(ChargerType.LAMP));
System.out.println(ChargerType.DISPLAY.getName() + " 电压:" + adapter.getVoltage(ChargerType.DISPLAY));
}
}
手机充电器 电压:5
笔记本充电器 电压:19
台灯充电器 电压:12
显示器充电器 电压:24
代码讲解:
-
接口定义:
Charger
接口定义了所有充电器类型共有的方法getName()
和getVoltage()
。
-
枚举类实现接口:
ChargerType
枚举类实现了Charger
接口,并定义了四种充电器类型:PHONE
、LAPTOP
、LAMP
、DISPLAY
。- 每个枚举值包含
name
和voltage
属性,分别表示充电器名称和电压。 getName()
和getVoltage()
方法分别返回枚举值的名称和电压。
-
适配器类:
ChargerAdapter
类充当适配器,它包含了四个私有属性,分别对应四种充电器类型。getVoltage()
方法接收一个ChargerType
枚举值作为参数,根据枚举值类型调用对应充电器的输出电压方法。- 这里使用了
switch
语句来判断枚举值类型,并调用对应充电器的输出电压方法。
能看到这里你已经基本掌握了开发中适配器模式的使用,还有一个问题,就是后续增加了新的充电器怎么办?要回去动Switch语句吗?怎么优化?
代码优化
使用 switch
语句虽然简单,但如果以后新增了充电器类型,就需要修改 ChargerAdapter
的代码,这违背了“开闭原则”。
1. 使用 Map
:
可以使用 Map
来存储充电器类型和对应充电器对象的映射关系。
class ChargerAdapter {
private Map<ChargerType, DeviceCharger> chargerMap = new HashMap<>();
public ChargerAdapter() {
chargerMap.put(ChargerType.PHONE, new PhoneCharger());
chargerMap.put(ChargerType.LAPTOP, new LaptopCharger());
chargerMap.put(ChargerType.LAMP, new LampCharger());
chargerMap.put(ChargerType.DISPLAY, new DisplayCharger());
}
public int getVoltage(ChargerType chargerType) {
DeviceCharger charger = chargerMap.get(chargerType);
if (charger != null) {
return charger.outputVoltage();
} else {
return 0;
}
}
}
这样,当新增充电器类型时,我们只需要在 chargerMap
中添加新的映射关系即可,无需修改 ChargerAdapter
的代码。
2. 使用反射:
我们可以使用反射机制来动态创建充电器对象。
class ChargerAdapter {
public int getVoltage(ChargerType chargerType) {
try {
Class<?> chargerClass = Class.forName(chargerType.name() + "Charger");
DeviceCharger charger = (DeviceCharger) chargerClass.newInstance();
return charger.outputVoltage();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return 0;
}
}
}
这样,当新增充电器类型时,我们只需要创建新的充电器类,并确保类名符合 ChargerType
枚举值的命名规范即可,无需修改 ChargerAdapter
的代码。
都看到这了,求大佬赏个赞赞