类的关系

图片说明

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、灵活性好。
  • 缺点:过多地使用适配器,会让系统非常零乱,不易整体进行把握。明明调用了这个接口,却可以实现其他接口的功能。