诗曰:
异国语言不相通,接口不配难交流。
适配器模式来相助,万国语言无障碍。
📖 故事
话说师徒四人来到"女儿国",此地人说的都是"女儿语",唐僧听不懂。
唐僧愁道:"悟空,这女儿国的语言,为师一句也听不懂啊!"
悟空笑道:"师父莫急!徒儿找个翻译,用适配器模式,让女儿语和唐语互通!"
🐉 踩坑打怪:接口不配之劫
第一劫:接口不兼容
java
// 女儿国翻译(女儿语接口)
public class NvErGuoTranslator {
public void translateFromNvEr(String nvErText) {
System.out.println("女儿语翻译:" + nvErText);
}
public String translateToNvEr(String tangText) {
return "女儿语:" + tangText;
}
}
// 唐僧(唐语接口)
public class TangSeng {
public void speak(String tangText) {
System.out.println("唐僧说:" + tangText);
}
public void listen(String tangText) {
System.out.println("唐僧听:" + tangText);
}
}
// 问题:接口不兼容!
// 女儿国国王想和唐僧对话,但接口对不上!
八戒抱怨: "猴哥!女儿国国王说女儿语,师父说唐语,咋交流?"
第二劫:强行适配
java
// 笨办法:修改原有类
public class TangSeng {
// 强行加女儿语方法
public void speakNvEr(String nvErText) {
// 翻译逻辑
String tangText = translate(nvErText);
speak(tangText);
}
private String translate(String nvErText) {
// 翻译逻辑...
return nvErText;
}
}
悟空摇头: "呆子!这违反了'开闭原则'!不能改原来的类!"
⚔️ 适配器模式大法
方式一:类适配器(继承)
java
// 目标接口:唐僧能理解的接口
public interface Translator {
String translateToTang(String foreignText);
String translateToForeign(String tangText);
}
// 被适配者:女儿国翻译
public class NvErGuoTranslator {
public void translateFromNvEr(String nvErText) {
System.out.println("女儿语翻译:" + nvErText);
}
public String translateToNvEr(String tangText) {
return "女儿语:" + tangText;
}
}
// 适配器:继承被适配者,实现目标接口
public class NvErAdapter extends NvErGuoTranslator implements Translator {
@Override
public String translateToTang(String foreignText) {
// 调用父类方法,转换成目标格式
System.out.println("【适配器】女儿语 → 唐语");
return foreignText.replace("女儿语:", "");
}
@Override
public String translateToForeign(String tangText) {
// 调用父类方法
return translateToNvEr(tangText);
}
}
方式二:对象适配器(组合,推荐)
java
// 适配器:持有被适配者的引用
public class NvErAdapter implements Translator {
private NvErGuoTranslator nvErTranslator; // 组合
public NvErAdapter(NvErGuoTranslator nvErTranslator) {
this.nvErTranslator = nvErTranslator;
}
@Override
public String translateToTang(String foreignText) {
System.out.println("【适配器】女儿语 → 唐语");
// 调用被适配者的方法
nvErTranslator.translateFromNvEr(foreignText);
return foreignText.replace("女儿语:", "");
}
@Override
public String translateToForeign(String tangText) {
System.out.println("【适配器】唐语 → 女儿语");
return nvErTranslator.translateToNvEr(tangText);
}
}
方式三:接口适配器(默认实现)
java
// 接口有很多方法,但有些用不上
public interface MultiTranslator {
String translateToTang(String text);
String translateToNvEr(String text);
String translateToWuLiang(String text); // 乌鸡国语
String translateToBaoXiang(String text); // 宝象国语
// ... 几十个国家的语言
}
// 抽象适配器:提供默认实现
public abstract class AbstractTranslator implements MultiTranslator {
@Override
public String translateToTang(String text) {
return text; // 默认不翻译
}
@Override
public String translateToNvEr(String text) {
return text;
}
@Override
public String translateToWuLiang(String text) {
return text;
}
@Override
public String translateToBaoXiang(String text) {
return text;
}
// ... 其他方法默认实现
}
// 具体适配器:只实现需要的方法
public class NvErSimpleAdapter extends AbstractTranslator {
@Override
public String translateToNvEr(String tangText) {
return "女儿语:" + tangText;
}
@Override
public String translateToTang(String nvErText) {
return nvErText.replace("女儿语:", "");
}
// 其他语言用默认实现(不翻译)
}
实战演练
java
public class Main {
public static void main(String[] args) {
// 创建女儿国翻译
NvErGuoTranslator nvErTranslator = new NvErGuoTranslator();
// 创建适配器
Translator adapter = new NvErAdapter(nvErTranslator);
// 女儿国国王说话
System.out.println("=== 女儿国国王说话 ===");
String nvErText = "女儿语:御弟哥哥,留下来吧!";
String tangText = adapter.translateToTang(nvErText);
System.out.println("唐僧听到:" + tangText);
// 唐僧回应
System.out.println("\n=== 唐僧回应 ===");
String tangReply = "贫僧要西天取经!";
String nvErReply = adapter.translateToForeign(tangReply);
System.out.println("女儿国国王听到:" + nvErReply);
}
}
输出:
=== 女儿国国王说话 ===
【适配器】女儿语 → 唐语
女儿语翻译:女儿语:御弟哥哥,留下来吧!
唐僧听到:御弟哥哥,留下来吧!
=== 唐僧回应 ===
【适配器】唐语 → 女儿语
女儿国国王听到:女儿语:贫僧要西天取经!
适配器模式的实战应用
Java 中的适配器
java
// Java IO 中的适配器
// InputStreamReader 是 InputStream 到 Reader 的适配器
InputStream inputStream = System.in;
Reader reader = new InputStreamReader(inputStream); // 适配器
// Java 集合中的适配器
// Collections.enumeration() 把 Iterator 适配成 Enumeration
List<String> list = Arrays.asList("A", "B", "C");
Enumeration<String> enumeration = Collections.enumeration(list);
Spring 中的适配器
java
// Spring MVC 中的 HandlerAdapter
// 把不同的 Controller 适配成统一的接口
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception;
}
🏆 战斗总结
唐僧赞叹: "悟空,这适配器模式果然精妙!不用改原来的类,就能让接口兼容!"
悟空得意: "师父,这还不止!适配器还能------"
| 优势 | 说明 |
|---|---|
| 复用旧代码 | 不用修改现有类 |
| 解决不兼容 | 让接口不同的类一起工作 |
| 符合开闭原则 | 对扩展开放,对修改封闭 |
本章要点
| 要点 | 说明 |
|---|---|
| 核心思想 | 将一个类的接口转换成客户期望的另一个接口 |
| 适用场景 | 接口不兼容、复用旧代码、第三方库集成 |
| 类型 | 类适配器、对象适配器、接口适配器 |
| 优点 | 复用旧代码、解决不兼容、符合开闭原则 |
| 缺点 | 增加复杂度、过度使用会增加系统混乱 |
下回预告
话说师徒继续西行,来到"万法归宗山"。法术太多太复杂,如何简化?且看外观模式!
欲知后事如何,且听第九回分解!