设计模式-适配器模式

500 阅读6分钟

文章结构 -什么是适配器模式-意义 -解决 - 关键代码-实例 -解释 -图解

什么是适配器模式

顾名思义,适配器模式就是两个不兼容的接口之间做适配和兼容,同时这个模式也是两种不兼容接口的链接桥梁,这种模式是属于结构性的,这个模式结合了两种独立的接口共功能,举个例子,加入你的电脑一个自带的播放器,只能播放mp4格式的视频播放器,如果有一天你需要播放mp3的音频,那么你可以使用你电脑的视频播放器(该功能视频播放器并没有是适配出来的模式)这样视频播放器就可以播放mp3的音频了
其实就是Mp3播放器可以播放视频的意思

意义

将一个接口的功能,转换为甲方需要的功能,使得原来不能在一起功能的功能,都集成到一个接口上面

解决

主要解决在后台软件中,将一个项目中的对象或者方法放到新的环境中,而新的环境或项目的接口不能满足原项目中对象的需求(若A有播放mp4视频的功能 B有播放Mp3的功能,那么当A需要播放Mp3时,但又没有Mp3的解码器,此时就可以用适配器模式,在Mp4里面提供一个Mp3的适配器)

关键代码

适配器继承或者依赖已有的对象,实现目标接口想要实现的功能

优点

可以让两个没有绝对联系的类一起运行,提高了代码的服用,增加了类的透明度,以及更好的灵活性,并且可以很好的解耦,降低对象之间的依赖

缺点

缺点就显而易见了,过多的使用适配器,会让一个类里面的逻辑操作,和后续的代码维护比较困难,当A代码调用时使用适配器适配到B代码 这样就调了一个项目,如果更多呢A->B->C->D... 那就处于一个不好维护的状态,当其中任意一环改变时,你的代码就会出现问题,所以适配器模式要适当使用

实例

步骤一: 创建一个媒体播放器,和一个高级的媒体播放器,在后续的步骤里面媒体播放器是作为适配方法的存在,而高级媒体播放器是提供指定方法的存在

MediaPlayer.java
public interface MediaPlayer {
    public void play(String audioType, String fileName);
}
AdvancedMediaPlayer.java
public interface AdvancedMediaPlayer {
    public void playVlc(String fileName);
    public void playMp4(String fileName);
}

步骤二: 创建实现高级媒体播放器的接口实现类,实现了Vlc和Mp4的功能,只是具体类只有具体的功能,实现了高级媒体播放器的功能

VlcPlayer.java
public class VlcPlayer implements AdvancedMediaPlayer{
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: "+ fileName);
    }

    @Override
    public void playMp4(String fileName) {
        //什么也不做
    }
}
Mp4Player.java
public class Mp4Player implements AdvancedMediaPlayer{

    @Override
    public void playVlc(String fileName) {
        //什么也不做
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: "+ fileName);
    }
}

步骤三:创建实现MediaPalyer接口的适配器类,也就是步骤一的MediaPlayer接口 并实现player方法来作为适配器方法使用,其他的就按照正常的AdvancedMediaPlayer的两个vlp和mp4方法来使用

MediaAdapter.java
public class MediaAdapter implements MediaPlayer {
    //引入了高级媒体播放器(vlc&&mp4)
    AdvancedMediaPlayer advancedMusicPlayer;
    
    //AdvancedMediaPlayer 构造器,提供创建某种对象的功能初始化字段
    public MediaAdapter(String audioType){
        if(audioType.equalsIgnoreCase("vlc") ){
            advancedMusicPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")){
            advancedMusicPlayer = new Mp4Player();
        }
    }
    
    //该方法来自于MediaPalyer 也就是一开始的媒体播放器类
    //该方法作为一个适配器方法,通过名称和构造器配合调用指定的方法
    @Override
    public void play(String audioType, String fileName) {
        if(audioType.equalsIgnoreCase("vlc")){
            advancedMusicPlayer.playVlc(fileName);
        }else if(audioType.equalsIgnoreCase("mp4")){
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

步骤四:创建MediaPalyer接口的实现类,该类的palyer是一种适配方法,如果传入的是Vlc或者Mp4功能那么就可以创建适配器类适配器类按照传入的格式初始化AdvancedMediaPlayer类就又了对应的播放器解析类的方法;

AudioPlayer.java
public class AudioPlayer implements MediaPlayer {
    MediaAdapter mediaAdapter;
    
    //该方法用于 
    @Override
    public void play(String audioType, String fileName) {

        //播放 mp3 音乐文件的内置支持
        if(audioType.equalsIgnoreCase("mp3")){
            System.out.println("Playing mp3 file. Name: "+ fileName);
        }
        //mediaAdapter 提供了播放其他文件格式的支持
        else if(audioType.equalsIgnoreCase("vlc")
                || audioType.equalsIgnoreCase("mp4")){
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        }
        else{
            System.out.println("Invalid media. "+
                    audioType + " format not supported");
        }
    }
}

步骤五:使用AudioPalyer来播放不同格式的音频格式,该方法调用的的逻辑 如果是mp3那么就是默认自带的播放方法,如果是mp4||vlc那么就使用适配器方法,创建高级媒体播放器的方法,如果是avi 那么就是被播放器的方法直接进行过滤

AdapterPatternDemo.java
public class AdapterPatternDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        audioPlayer.play("mp3", "beyond the horizon.mp3");
        audioPlayer.play("mp4", "alone.mp4");
        audioPlayer.play("vlc", "far far away.vlc");
        audioPlayer.play("avi", "mind me.avi");
    }
}

输出结果:

Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported

解释:

适配器模式,整个的流程和逻辑从下向上,从适配器模式的Demo开始说起,如果传入的是mp3那么就是自带的播放方法,不使用适配器类进行适配,如果使用的是mp4||vlc那么播放器在调用player方法的时候,创建媒体播放适配器的类,同时媒体播放器类初始化了对应的对象VlcPalyer||Mp4Player或者对象,这两个对象继承了AdvanceMediaPlayer自带播放功能,在媒体播放器类里面(AudioPlayer)创建完媒体播放器适配器类调用了player 并将类型和文件名称传入,此时适配器类会根据文件名称调用对应的播放方法 也就是 playVlc(fileName);和playMp4(fileName);方法,接下来的就是执行真正的方法了;

图解

我们有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。

我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。

我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。

AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,不需要知道能播放所需格式音频的实际类。AdapterPatternDemo 类使用 AudioPlayer 类来播放各种格式。 image.png