你有没有遇到过这样的场景:出国旅行,想给手机充电,却发现酒店的插座和自己的充电器插头不匹配?这时候,一个转换插头就能完美解决问题,它能把酒店插座的接口,转换成充电器能适配的接口。在 Java 编程世界里,也有类似的 “转换插头”,它就是适配器设计模式。接下来,就让我们一起揭开它的神秘面纱。
一、什么是适配器设计模式
适配器设计模式(Adapter Design Pattern)属于结构型设计模式,它的核心作用是将一个类的接口转换成客户希望的另一个接口 。就像上述提到的转换插头,在程序中,当我们有两个不兼容的接口,而又希望它们能协同工作时,适配器就派上用场了。通过适配器,原本无法合作的类可以顺利交互,让代码的扩展性和复用性大大提高。
二、适配器设计模式的类型
在 Java 中,适配器设计模式主要有两种类型:对象适配器和类适配器。
1.Java 中 220V 转换为 6V 的 类适配器 实现
类适配器是通过继承(Is - A)的方式来实现的。它继承被适配类,同时实现目标接口。不过,由于 Java 不支持多重继承,所以类适配器的使用场景相对较少。
⑴.中文实现思路
🧠 实现思路总结
⚙️ 中文代码实现
1.目标接口:手机充电器(6V)
/**
* 手机充电器接口,定义6V低压输出标准
*/
public interface 手机充电器 {
void 提供低压(); // 提供6V电压
}
2. 适配者:插座(220V)
/**
* 插座类,提供220V高压电
*/
public class 插座 {
public int 获取高压() {
System.out.println("⚡ 插座提供 220V 高压电");
return 220;
}
}
3. 类适配器:电压转换器(继承 + 实现)
/**
* 电压适配器类(类适配器):继承 插座 类并实现 手机充电器 接口
*/
public class 电压适配器 extends 插座 implements 手机充电器 {
@Override
public void 提供低压() {
int 高压 = 获取高压(); // 调用继承自 插座 的方法
int 低压 = 高压 / 37; // 模拟电压转换(220 / 37 ≈ 6)
System.out.println("🔌 适配器将 220V 转换为 " + 低压 + "V 低压电");
}
}
4. 客户端:手机充电
/**
* 手机类,依赖手机充电器接口进行充电
*/
public class 手机 {
public void 充电(手机充电器 充电器) {
System.out.println("🔋 手机开始充电...");
充电器.提供低压();
System.out.println("✅ 充电完成!");
}
}
5. 测试运行
public class 测试 {
public static void main(String[] args) {
// 创建适配器(类适配器)
电压适配器 适配器 = new 电压适配器();
// 创建手机
手机 手机 = new 手机();
// 使用适配器给手机充电
手机.充电(适配器);
}
}
运行结果:
⑵英文代码
角色定义
角色 | 描述 |
---|---|
目标接口(Target) | MobileCharger ,定义手机所需的 6V 输出接口。 |
适配者(Adaptee) | Socket ,提供 220V 高压电。 |
适配器(Adapter) | VoltageAdapter ,继承 Socket 并实现 MobileCharger ,将 220V 转换为 6V。 |
⚙️ 代码实现
1. 目标接口:手机充电器(6V)
/**
* 手机充电器接口,定义6V低压输出标准
*/
public interface MobileCharger {
void deliverLowVoltage(); // 提供6V电压
}
2. 适配者:插座(220V)
/**
* 插座类,提供220V高压电
*/
public class Socket {
public int getHighVoltage() {
System.out.println("⚡ 插座提供 220V 高压电");
return 220;
}
}
3. 类适配器:电压转换器(继承 + 实现)
/**
* 电压适配器类(类适配器):继承 Socket 类并实现 MobileCharger 接口
*/
public class VoltageAdapter extends Socket implements MobileCharger {
@Override
public void deliverLowVoltage() {
int highVoltage = getHighVoltage(); // 调用继承自 Socket 的方法
int lowVoltage = highVoltage / 37; // 模拟电压转换
System.out.println("🔌 适配器将 220V 转换为 " + lowVoltage + "V 低压电");
}
}
4. 客户端:手机充电
/**
* 手机类,依赖手机充电器接口进行充电
*/
public class Phone {
public void charge(MobileCharger charger) {
System.out.println("🔋 手机开始充电...");
charger.deliverLowVoltage();
System.out.println("✅ 充电完成!");
}
}
5. 测试运行
public class Test {
public static void main(String[] args) {
// 创建适配器(类适配器)
VoltageAdapter adapter = new VoltageAdapter();
// 创建手机
Phone phone = new Phone();
// 使用适配器给手机充电
phone.charge(adapter);
}
}
运行结果
⚡ 插座提供 220V 高压电
🔌 适配器将 220V 转换为 6V 低压电
🔋 手机开始充电...
✅ 充电完成!
在 Java 中虽然不支持多继承,但只要适配者是一个类,而目标是一个接口,就可以通过 继承类并实现接口 的方式实现类适配器。
- 在 Java 中,只要适配者是一个类,而目标是一个接口,就可以使用类适配器。
- 如果你希望代码更灵活、适配器与适配者解耦,建议使用 对象适配器。
2.Java 中 220V 转换为 6V 的 对象适配器 实现
⑴.Java 适配器设计模式:220V 电源给 6V 手机充电(中文代码版)
实现思路总结
中文代码实现
1. 目标接口:手机充电器(6V)
/**
* 手机充电器接口,定义6V低压输出标准
*/
public interface 手机充电器 {
void 提供低压(); // 提供6V电压
}
2. 适配者:插座(220V)
/**
* 插座类,提供220V高压电
*/
public class 插座 {
public int 获取高压() {
System.out.println("⚡ 插座提供 220V 高压电");
return 220;
}
}
3. 适配器:电压转换器
/**
* 电压适配器,将220V转换为6V
*/
public class 电压适配器 implements 手机充电器 {
private 插座 插座;
public 电压适配器(插座 插座) {
this.插座 = 插座;
}
@Override
public void 提供低压() {
int 高压 = 插座.获取高压();
int 低压 = 高压 / 37; // 简化模拟:220 / 37 ≈ 6V
System.out.println("🔌 适配器将 220V 转换为 " + 低压 + "V 低压电");
}
}
4. 客户端:手机充电
/**
* 手机类,依赖手机充电器接口进行充电
*/
public class 手机 {
public void 充电(手机充电器 充电器) {
System.out.println("🔋 手机开始充电...");
充电器.提供低压();
System.out.println("✅ 充电完成!");
}
}
5. 测试运行
public class 测试 {
public static void main(String[] args) {
插座 插座 = new 插座(); // 创建220V插座
电压适配器 适配器 = new 电压适配器(插座); // 创建适配器
手机 手机 = new 手机(); // 创建手机
手机.充电(适配器); // 使用适配器给手机充电
}
}
运行结果:
⑵英文代码
角色划分
适配器模式有三个核心角色:
角色 | 描述 |
---|---|
目标接口(Target) | 客户端期望的接口,这里是 MobileCharger ,提供 6V 的低压输出。 |
适配者(Adaptee) | 需要被适配的接口或类,这里是 Socket ,提供 220V 的高压输出。 |
适配器(Adapter) | 桥接目标与适配者的中间层,这里是 VoltageAdapter ,将 220V 转换为 6V。 |
⚙️代码实现
1. 目标接口:手机充电器(6V)
// 手机充电器接口,提供 6V 低压输出
public interface MobileCharger {
void deliverLowVoltage(); // 提供低压电
}
2. 适配者:插座(220V)
// 插座类,提供 220V 高压输出
public class Socket {
public int getHighVoltage() {
System.out.println("⚡ 插座提供 220V 高压电");
return 220;
}
}
3. 适配器:电压转换器
// 电压适配器,将 220V 转换为 6V
public class VoltageAdapter implements MobileCharger {
private Socket socket;
public VoltageAdapter(Socket socket) {
this.socket = socket;
}
@Override
public void deliverLowVoltage() {
int highVoltage = socket.getHighVoltage();
int lowVoltage = highVoltage / 37; // 简化模拟:220 / 37 ≈ 6
System.out.println("🔌 适配器将 220V 转换为 " + lowVoltage + "V 低压电");
}
}
4. 客户端:手机充电
// 手机类,依赖 MobileCharger 接口进行充电
public class Phone {
public void charge(MobileCharger charger) {
System.out.println("🔋 手机开始充电...");
charger.deliverLowVoltage();
System.out.println("✅ 充电完成!");
}
}
测试运行
public class Client {
public static void main(String[] args) {
Socket socket = new Socket(); // 创建 220V 插座
VoltageAdapter adapter = new VoltageAdapter(socket); // 创建适配器
Phone phone = new Phone(); // 创建手机
phone.charge(adapter); // 使用适配器给手机充电
}
}
三、适配器用的比较多的地方
适配器设计模式更多的是代码层面上的变化,
比如我有一个接口,接口中有10个方法,如果我写一个类去实现这个接口,那必然要把接口中的所有方法都要重写,但实际情况呢!
是有可能我只用到了一个方法,其他的9个方法呢?我都不用去写代码,但是这个9个方法会写在我这个类中,觉得这9个方法有点碍事,那怎么办呢?
所以我们需要加一层中间层,这个中间层怎么加呢?重新写一个类去实现这个接口,然后去重写这个接口的所有方法,这时候你写的那个类呢?只要去继承这个类,然后去选择性的去重写某个方法,
通过这种方式,你就可以摆脱不相干的那9个方法,这个中间层就叫做适配器,这个也是适配器用的比较多的地方
适配器设计模式:解决接口方法冗余问题的代码示例
Java 接口的特性决定了实现类必须重写所有方法(除非该类是抽象类)。当接口方法很多而子类只需部分方法时,直接实现接口会导致大量冗余代码。此时使用 ** 接口适配器模式(缺省适配器)** 是最佳解决方案:
问题场景
当一个接口有多个方法(如10个),但具体实现类只需要用到其中1个方法时,强制实现所有方法会导致代码冗余。
解决方案:通过适配器类(Adapter)提供默认空实现,让具体类只重写需要的方法。
1. 定义接口(包含10个方法)
public interface MyInterface {
void m1();
void m2();
void m3();
void m4();
void m5();
void m6();
void m7();
void m8();
void m9();
void m10();
}
2. 创建适配器类(中间层)
public abstract class Adapter implements MyInterface {
@Override
public void m1() {} // 默认空实现
@Override
public void m2() {}
@Override
public void m3() {}
@Override
public void m4() {}
@Override
public void m5() {}
@Override
public void m6() {}
@Override
public void m7() {}
@Override
public void m8() {}
@Override
public void m9() {}
@Override
public void m10() {}
}
3. 具体类:只重写需要的方法
public class ConcreteClass extends Adapter {
@Override
public void m1() {
System.out.println("✅ Method m1 is implemented.");
}
}
4. 客户端代码:使用适配器简化实现
public class Client {
public static void main(String[] args) {
MyInterface myInterface = new ConcreteClass();
myInterface.m1(); // 输出: ✅ Method m1 is implemented.
myInterface.m2(); // 无输出(由适配器提供空实现)
}
}
四、适配器使用场景——功能合并
还有一种做法,我有一个别人写的类,这个类呢?不能去修改它,我又想把它融合在我的类中,
这种呢?叫做功能合并,就是把别人的功能合并到我的功能里面来——怎么办呢?比如A类中有一个m1方法,有一个B接口,接口中2个方法,一个叫m1,一个叫m2,我现在只想实现m2方法,m1方法呢?让他去调用a类的方法,a类呢?又不是我自己写的,又不能去修改别人的类,
这时候,你只需要写一个新的类去继承a类,实现b接口,然后在你的新类里面重写m2方法,这样b接口中的m1方法就自动转向了a类上的m1方法,这就是让原本没有办法合作在一起的,让它合作在一起。这种操作有点像多继承,其实在java之中,虽然不支持你类上面的多继承,但是它还是支持你继承一个类,实现多个接口的这种方式
以下是针对该场景的代码实现,通过继承不可修改的类 A
并实现接口 B
,使新类 C
既能复用 A
的 m1
方法,又能实现 B
接口中的 m2
方法:
1.这个是类适配器
// 定义不可修改的类A,包含m1方法
class A {
public void m1() {
System.out.println("执行 A 类的 m1 方法");
}
}
// 定义接口B,包含m1和m2方法
interface B {
void m1();
void m2();
}
// 新类C继承A并实现B
class C extends A implements B {
// 无需显式重写m1方法,直接继承A的m1方法
@Override
public void m2() {
System.out.println("执行 B 接口中 C 类实现的 m2 方法");
}
}
// 测试类
public class Main {
public static void main(String[] args) {
C instance = new C();
// 调用从A类继承的m1方法
instance.m1();
// 调用C类实现的m2方法
instance.m2();
}
}
代码解析:
- 类
A
:表示不可修改的外部类,包含方法m1
。 - 接口
B
:定义了两个方法m1
和m2
,要求实现类提供这两个方法的具体逻辑。 - 类
C
:- 继承自类
A
,从而直接复用A
中的m1
方法。 - 实现接口
B
,仅需显式重写m2
方法(m1
方法由继承自A
的实现来满足接口要求)。
- 继承自类
- 测试类
Main
:创建C
的实例,分别调用m1
和m2
方法,验证功能合并的效果。
这种方式利用了 Java 中 “单继承 + 多接口实现” 的特性,在不修改类 A
的前提下,将类 A
的功能与接口 B
的定义整合到新类 C
中,实现了 “功能合并”,使原本独立的类和接口得以协同工作。
2.改用对象适配器
定义类 A(原始类)
class A {
public void m1() {
System.out.println("A类的m1方法");
}
}
定义接口 B(目标接口)
interface B {
void mm1();
void mm2();
}
创建对象适配器类
核心思路(手写):在适配器中重写mm1方法,mm1方法中使用a对象调用m1方法
class ObjectAdapter implements B {
private final A a; // 组合类A的对象
public ObjectAdapter() {
this.a = new A();
}
@Override
public void mm1() {
a.m1(); // 调用类A的m1方法来实现接口B的mm1方法
}
@Override
public void mm2() {
System.out.println("实现B接口的mm2方法");
}
}
测试类(客户端调用)
public class Main {
public static void main(String[] args) {
B adapter = new ObjectAdapter();
adapter.mm1(); // 输出:A类的m1方法
adapter.mm2(); // 输出:实现B接口的mm2方法
}
}