类的关系
UML类图
大致理解
我们有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。
我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 mp5 和 mp4 格式的文件。
我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象(接口)来播放所需的格式。
代码分析
最原始的接口MediaPlayer
public interface MediaPlayer { public void play(String audioType, String fileName); }
扩展功能的接口 AdvancedMediaPlayer
public interface AdvancedMediaPlayer { public void playMp5(String fileName); public void playMp4(String fileName); }
先理解扩展功能的实现类(2个)
public class Mp5Player implements AdvancedMediaPlayer{ @Override public void playMp5(String fileName) { System.out.println("播放Mp5文件: "+ fileName); } @Override public void playMp4(String fileName) { //什么也不做 } } public class Mp4Player implements AdvancedMediaPlayer{ @Override public void playMp5(String fileName) { //什么也不做 } @Override public void playMp4(String fileName) { System.out.println("播放MP4文件 "+ fileName); } }
最原始mp3功能的实现类(后续会迭代)
public class AudioPlayer implements MediaPlayer { @Override public void play(String audioType, String fileName) { //播放 mp3 音乐文件的内置支持 if(audioType.equals("mp3")){ System.out.println("播放Mp3: "+ fileName); } else{ System.out.println("以下 "+ audioType + "格式不支持"); } } }
显然,如果没有适配器,最原始和扩展功能是无法联系在一起的,因此此时我们加入适配器后,要将相应的代码进行修改
因此先理解适配器的实现
可以清晰的看到,适配器中,有一个扩展接口AdvancedMediaPlayer对象,根据传入的参数,判断使用哪个扩展功能。
public class MediaAdapter implements MediaPlayer { AdvancedMediaPlayer advancedPlayer; //构造器 public MediaAdapter(String audioType){ if(audioType.equals("mp5") ){ advancedPlayer = new Mp5Player(); } else if (audioType.equals("mp4")){ advancedPlayer = new Mp4Player(); } } @Override public void play(String audioType, String fileName) { if(audioType.equals("mp5")){ advancedPlayer.playMp5(fileName); }else if(audioType.equals("mp4")){ advancedPlayer.playMp4(fileName); } } }
重中之重 基础实现类代码迭代
我们添加了适配器,必然要修改之前实现的AudioPlayer,也就是普通播放功能的类,因为我们期望普通播放类中可以完成扩展功能。(原本只能播放mp3现在能放mp5)
public class AudioPlayer implements MediaPlayer { MediaAdapter mediaAdapter; @Override public void play(String audioType, String fileName) { //播放 mp3 音乐文件的内置支持 if(audioType.equals("mp3")){ System.out.println("播放Mp3: "+ fileName); } //mediaAdapter 提供了播放其他文件格式的支持 else if(audioType.equals("mp5") || audioType.equals("mp4")){ mediaAdapter = new MediaAdapter(audioType); mediaAdapter.play(audioType, fileName); } else{ System.out.println("以下 "+ audioType + "格式不支持"); } } }
可以看到,当传入的是Mp4时,我们会new一个适配器对象处理,并告诉它具体格式是什么(构造器传参数),然后调用对应的播放功能,也就是说,在基础实现类中,我们会新建一个适配器对象,然后用适配器去实现扩展的功能。
Demo类主方法
public class Demo { public static void main(String[] args) { AudioPlayer audioPlayer = new AudioPlayer(); audioPlayer.play("mp3", "音乐.mp3"); audioPlayer.play("mp4", "视频.mp4"); audioPlayer.play("mp5", "进阶视频.mp5"); audioPlayer.play("avi", "开车.avi"); } }
测试结果:
播放Mp3: 音乐.mp3 播放MP4文件 视频.mp4 播放Mp5文件: 进阶视频.mp5 以下 avi格式不支持
总结:
- 当你学习设计模式的时候,基础要打牢,这里的多态体现的淋漓尽致。适配器中会new接口对象,然后利用多态拿到具体的实现类,并完成播放功能,真的是妙妙妙啊。
- 另外我们可以看到,中间有一个迭代过程,也说明了适配器模式不是在项目一开始就设计好的,而是解决正在服役的项目需要扩展功能的时候出现的。并且这个扩展功能并不是当前类的扩展,而是其他类,这里的扩展是指整个系统上的扩展。
- 优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。
- 缺点:过多地使用适配器,会让系统非常零乱,不易整体进行把握。明明调用了这个接口,却可以实现其他接口的功能。