2025/9/24日 每日总结 设计模式实践:双向适配器模式之"猫狗互学技能"案例解析
设计模式实践:双向适配器模式之"猫狗互学技能"案例解析
在软件开发中,经常会遇到两个已存在的接口因设计不同而无法直接协作的问题。适配器模式作为一种经典的结构型设计模式,能够在不修改原有代码的前提下,让不兼容的接口相互配合。本文将通过"猫学狗叫、狗学猫抓老鼠"的趣味案例,详细拆解双向适配器模式的实现逻辑与应用场景。
一、实验背景与需求
本次实践的核心需求是构建一个双向适配器,实现两种不同动物接口的技能互通:
-
猫(Cat)接口原有行为:叫(cry)、抓老鼠(catchMouse)
-
狗(Dog)接口原有行为:叫(wang)、行动(action)
-
适配目标:让猫能学狗叫,让狗能学猫抓老鼠
-
约束:不修改Cat和Dog的原有接口及实现类,保持原有功能不变
二、双向适配器模式核心结构
双向适配器模式的关键在于适配器类同时实现两个目标接口,并持有两个接口的实例引用,通过转发调用实现双向适配。本次案例的结构设计如下:
1. 核心组件划分
| 组件类型 | 具体实现 | 职责描述 |
|---|---|---|
| 目标接口A | Cat | 定义猫的行为规范(cry、catchMouse) |
| 目标接口B | Dog | 定义狗的行为规范(wang、action) |
| 具体实现类A | ConcreteCat | 实现Cat接口的原生行为 |
| 具体实现类B | ConcreteDog | 实现Dog接口的原生行为 |
| 双向适配器 | Adapter | 同时实现Cat和Dog接口,持有两个接口实例,实现行为转发 |
2. 类图结构
┌───────────────┐ ┌───────────────┐
│ Cat │ │ Dog │
├───────────────┤ ├───────────────┤
│ + cry() │ │ + wang() │
│ + catchMouse()│ │ + action() │
└───────────────┘ └───────────────┘
▲ ▲
│ │
└───────────┬───────────┘
│
┌───────────────┐
│ Adapter │
├───────────────┤
│ - cat: Cat │
│ - dog: Dog │
│ + setCat() │
│ + setDog() │
│ + cry() │ // 适配Cat接口,转发为Dog的wang()
│ + catchMouse()│ // 保留Cat原生行为
│ + wang() │ // 保留Dog原生行为
│ + action() │ // 适配Dog接口,转发为Cat的catchMouse()
└───────────────┘
│
┌─────────┴─────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ConcreteCat │ │ConcreteDog │
├───────────────┤ ├───────────────┤
│ + cry() │ │ + wang() │
│ + catchMouse()│ │ + action() │
└───────────────┘ └───────────────┘
三、完整实现代码
1. 核心接口定义
Cat接口(猫行为规范)
/**
* 猫接口,定义猫的基础行为
*/
public interface Cat {
// 猫叫
void cry();
// 猫抓老鼠
void catchMouse();
}
#### Dog接口(狗行为规范)
```java
/**
* 狗接口,定义狗的基础行为
*/
public interface Dog {
// 狗叫
void wang();
// 狗行动
void action();
}
2. 接口实现类(原生行为)
具体猫类:ConcreteCat.java
/**
* 猫接口的具体实现,实现猫的原生行为
*/
public class ConcreteCat implements Cat {
@Override
public void cry() {
System.out.println("猫叫");
}
@Override
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
具体狗类:ConcreteDog.java
/**
* 狗接口的具体实现,实现狗的原生行为
*/
public class ConcreteDog implements Dog {
@Override
public void wang() {
System.out.println("狗叫");
}
@Override
public void action() {
System.out.println("狗行动");
}
}
3. 双向适配器类:Adapter.java
/**
* 双向适配器,同时实现Cat和Dog接口,实现技能互通
*/
public class Adapter implements Dog, Cat {
// 持有Cat和Dog的实例引用
private Cat cat;
private Dog dog;
// Getter和Setter方法
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
// 实现Cat接口的cry():猫学狗叫
@Override
public void cry() {
System.out.print("猫学");
dog.wang(); // 转发为Dog的wang()方法
}
// 实现Cat接口的catchMouse():保留猫的原生行为
@Override
public void catchMouse() {
cat.catchMouse();
}
// 实现Dog接口的wang():保留狗的原生行为
@Override
public void wang() {
dog.wang();
}
// 实现Dog接口的action():狗学猫抓老鼠
@Override
public void action() {
System.out.print("狗学");
cat.catchMouse(); // 转发为Cat的catchMouse()方法
}
}
4. 测试类:Test.java
/**
* 测试类,验证双向适配器的功能
*/
public class Test {
public static void main(String args[]) {
// 创建原生实例
Cat cat1 = new ConcreteCat();
Dog dog1 = new ConcreteDog();
// 创建双向适配器并设置适配对象
Adapter adapter = new Adapter();
adapter.setCat(cat1);
adapter.setDog(dog1);
System.out.println("=== 猫的行为测试 ===");
// 猫的原生行为:抓老鼠
cat1 = (Cat) adapter;
cat1.catchMouse();
// 猫的适配行为:学狗叫
cat1.cry();
System.out.println("\n=== 狗的行为测试 ===");
// 狗的适配行为:学猫抓老鼠
dog1 = (Dog) adapter;
dog1.action();
// 狗的原生行为:叫
dog1.wang();
}
}
四、运行结果
=== 猫的行为测试 ===
猫抓老鼠
猫学狗叫
=== 狗的行为测试 ===
狗学猫抓老鼠
狗叫
从运行结果可以看出:
-
猫保留了原生的"抓老鼠"行为,同时通过适配器获得了"学狗叫"的新能力
-
狗保留了原生的"狗叫"行为,同时通过适配器获得了"学猫抓老鼠"的新能力
-
原有接口和实现类的代码未做任何修改,完全符合开闭原则
五、双向适配器模式核心优势
-
双向兼容:一个适配器同时解决两个接口的兼容性问题,实现双向通信
-
低耦合:无需修改原有接口和实现类,将适配逻辑集中在适配器中,降低系统耦合
-
透明性:客户端可以像使用原生接口一样使用适配器,无需关注适配细节
-
高复用:适配器可以在多个场景中重复使用,提高代码复用率
-
符合开闭原则:扩展新的适配功能时,只需修改适配器,无需改动原有系统
六、适用场景总结
双向适配器模式特别适合以下场景:
- 两个已存在的接口需要相互协作,但接口设计不兼容
- 希望在不修改原有代码的前提下,为两个接口添加互通功能
- 系统需要同时支持两种不同的接口规范,且要求客户端透明使用
- 需复用两个接口的实现类,且希望它们能协同工作
通过本次"猫狗互学技能"的实践案例,深刻体会到双向适配器模式在解决接口兼容性问题时的灵活性。它不仅能让原本不相关的接口相互协作,还能在不破坏原有系统设计的前提下扩展功能,是软件设计中不可或缺的重要模式。在实际开发中,当遇到遗留系统接口适配、第三方组件集成等场景时,双向适配器模式会是一个非常理想的解决方案。

浙公网安备 33010602011771号