适配器模式(Adapter Pattern)
适配器模式是一种 结构型设计模式,用于将一个类的接口转换成客户希望的另一个接口,使得原本接口不兼容的类可以一起工作。
原理
- 核心思想:通过创建一个适配器类来包装原始类(或对象),并在适配器中实现目标接口,从而解决接口不兼容的问题。
- 适用场景:
- 系统需要使用现有的类,但这些类的接口与需求不匹配。
- 需要重用一些现有的类,而这些类的接口与新系统不一致。
- 参与角色:
- Target(目标接口):定义客户期望的接口。
- Adaptee(被适配者):需要适配的现有类。
- Adapter(适配器):将被适配者转换成目标接口。
优点
- 提高代码复用性:通过适配器复用现有的类。
- 灵活性高:解耦目标接口与被适配者,实现系统扩展。
- 易于实现和使用:适配器的实现通常较为简单。
缺点
- 复杂度增加:可能需要引入额外的适配器类。
- 性能问题:在一些情况下,可能会增加系统的复杂性和运行成本。
示例代码
场景描述
假设有一个现有的 AudioPlayer
类,它只能播放 MP3
格式的音频,但现在需要支持其他格式(如 MP4
和 VLC
)。我们使用适配器模式来实现这个功能。
1. 定义目标接口
// 目标接口
public interface MediaPlayer {void play(String audioType, String fileName);
}
2. 定义被适配者
// 被适配者类
public class AdvancedMediaPlayer {public void playMp4(String fileName) {System.out.println("Playing MP4 file: " + fileName);}public void playVlc(String fileName) {System.out.println("Playing VLC file: " + fileName);}
}
3. 创建适配器类
// 适配器类
public class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMediaPlayer;public MediaAdapter(String audioType) {if ("MP4".equalsIgnoreCase(audioType)) {advancedMediaPlayer = new AdvancedMediaPlayer() {@Overridepublic void playMp4(String fileName) {System.out.println("Adapting MP4 playback for: " + fileName);}};} else if ("VLC".equalsIgnoreCase(audioType)) {advancedMediaPlayer = new AdvancedMediaPlayer() {@Overridepublic void playVlc(String fileName) {System.out.println("Adapting VLC playback for: " + fileName);}};}}@Overridepublic void play(String audioType, String fileName) {if ("MP4".equalsIgnoreCase(audioType)) {advancedMediaPlayer.playMp4(fileName);} else if ("VLC".equalsIgnoreCase(audioType)) {advancedMediaPlayer.playVlc(fileName);}}
}
4. 创建具体实现类
// 具体实现类
public class AudioPlayer implements MediaPlayer {private MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if ("MP3".equalsIgnoreCase(audioType)) {System.out.println("Playing MP3 file: " + fileName);} else if ("MP4".equalsIgnoreCase(audioType) || "VLC".equalsIgnoreCase(audioType)) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("Invalid media type: " + audioType);}}
}
5. 客户端代码
public class AdapterPatternExample {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("MP3", "song.mp3");audioPlayer.play("MP4", "movie.mp4");audioPlayer.play("VLC", "documentary.vlc");audioPlayer.play("AVI", "random.avi");}
}
输出结果
Playing MP3 file: song.mp3
Adapting MP4 playback for: movie.mp4
Adapting VLC playback for: documentary.vlc
Invalid media type: AVI
UML 类图
+----------------+| MediaPlayer |+----------------+| + play() |+----------------+^|+----------------+| AudioPlayer |+----------------+| + play() |+----------------+^|+----------------+| MediaAdapter |+----------------+| - advancedMedia|| + play() |+----------------+^|+----------------+|AdvancedMedia |+----------------+|+ playMp4() ||+ playVlc() |+----------------+
适用场景
- 接口不兼容:现有类的接口不满足需求,但又无法直接修改类。
- 封装遗留代码:需要对老旧系统进行封装,以适应新的系统需求。
- 不同模块集成:需要集成第三方库或系统,但接口形式不同。
总结
- 适配器模式解决了接口不兼容的问题,使得原本无法协作的类能够一起工作。
- 它既可以应用于 类适配器模式(通过继承实现),也可以应用于 对象适配器模式(通过组合实现)。
- 实际开发中,适配器模式在系统迁移、集成第三方库等场景中非常常见。