1.7(设计模式)适配器模式

适配器主要解决适配问题,即将一些由于接口不兼容不能一起工作的类可以在一起工作。

例如插座上是220v的电压,手机充电需要5v的电压,这时手机和插座直接就通过一个适配器(充电器)连接起来了。

例如一个音频播放器只能播放MP3格式的文件,我们通过一个适配器将其连接到高级播放器上,

当前音频播放器不支持的格式(MP4、VLC)转交给高级播放器播放,使其能播放更多格式。

下面就媒体播放器这个例子看下对应代码:

媒体文件类型

public enum AudioTypeEnum {
    MP3,VLC,MP4
}

高级媒体播放器接口,可以播放MP4/VLC格式的文件。后续高级媒体播放器与媒体播放器通过适配器连接,使媒体播放器可以支持更多格式。

这个接口和实现类可以暂且不看,等后续添加适配器的时候再看这一部分。

public interface AdvanceMediaPlay {
    public void playMp4(String fileName);
    public void playVlc(String fileName);
}

高级媒体播放器 播放MP4格式文件的具体实现类

public class Mp4Play implements AdvanceMediaPlay{

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

    @Override
    public void playVlc(String fileName) {}
    
}

高级媒体播放器 播放VLC格式的具体实现类

public class VlcPlay implements AdvanceMediaPlay{

    @Override
    public void playMp4(String fileName) {}

    @Override
    public void playVlc(String fileName) {
        System.out.println("play vlc:" + fileName);
    }

}

 (上述部分可暂且忽略,等后续添加适配器时再查看)

 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

媒体播放器接口,主要包含播放方法,方法参数:媒体文件类型(MP3、MP4、VLC),文件名

public interface MediaPlay {
    public void paly(AudioTypeEnum audioType, String fileName);
}

实现媒体播放接口的音频播放器,音频播放器只能实现播放MP3格式的文件。

public class AudioPlay implements MediaPlay{
    //private MediaAdapter mediaAdapter;

    
    public void paly(AudioTypeEnum audioType, String fileName) {
        
        switch(audioType) {
        case MP3://内置MP3播放器
            System.out.println("play mp3:" + fileName);
            break;
        case MP4://TODO 其他可播放类型,采用适配器播放

        default://TODO 无法播放部分抛出异常
            try {
                throw new Exception("播放异常,格式不支持!");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }    
}

我们先来看下没有添加适配器,只能播放MP3格式的情况,此时将高级媒体播放器看做与其无关的一个个体。

目前有两个个体,一个是音频播放器,一个是高级媒体播放器。

测试音频播放器

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MediaPlay mediaPlay = new AudioPlay();
        mediaPlay.paly(AudioTypeEnum.MP4, "mmm4");
        mediaPlay.paly(AudioTypeEnum.MP3, "mmm3");
        mediaPlay.paly(AudioTypeEnum.VLC, "fff");
    }

}
java.lang.Exception: 播放异常,格式不支持!
play mp3:mmm3
    at com.design.adapter.AudioPlay.paly(AudioPlay.java:20)
    at com.design.adapter.Main.main(Main.java:8)
java.lang.Exception: 播放异常,格式不支持!
    at com.design.adapter.AudioPlay.paly(AudioPlay.java:20)
    at com.design.adapter.Main.main(Main.java:10)

 可以看到,只有音频播放器支持的MP3格式可以正常播放,其他格式都无法播放。

此时有一个高级媒体播放器可以播放其他类型的媒体文件,我们有没有什么办法将音频播放器和高级媒体播放器联系起来?

当然有,那就是适配器。

现在我们想通过一个适配器将两者联系起来,让音频播放器可以通过高级媒体播放器播放更多类型的信息。

既然适配器是对传入音频播放器的文件进行适配,将其适配到高级媒体播放器中播放,那么首先适配器需要和音频播放器一样实现MediaPlay接口。

public class MediaAdapter implements MediaPlay{
    
    public MediaAdapter(AudioTypeEnum audioTypeEnum) {
       
    }
    
    @Override
    public void paly(AudioTypeEnum audioType, String fileName) {
        
    }
}

适配器最终是调用高级媒体播放器播放文件,最终播放具体文件还是高级媒体播发器接口的实现类来完成的。

所有在创建适配器对象时,我们可以根据文件类型,实例化一个播放该文件的播放器。

public class MediaAdapter implements MediaPlay{
    AdvanceMediaPlay advanceMediaPlay;
    //根据类型,适配对应对象,最后通过具体对象播放文件
    public MediaAdapter(AudioTypeEnum audioTypeEnum) {
        switch (audioTypeEnum) {//是什么类型的对象,就实例化什么类型的播放器
        case MP4:advanceMediaPlay = new Mp4Play();
            break;
        case VLC:advanceMediaPlay = new VlcPlay();
            break;
        default:
            try {
                throw new Exception("播放类型异常!");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    //根据类型,适配对应方法
    @Override
    public void paly(AudioTypeEnum audioType, String fileName) {
        
    }
}

具体的播放对象实例完成后,我们来看看paly方法,现在确定了基本的思路。音频播放器将不支持的文件传递给适配器,

适配器调用对应的播放器来播放文件。

AdvanceMediaPlay 中有playMp4和palyVlc两个播放方法,这时在适配器的paly中需要根据文件类型,调用对用的方法。

例如实例化适配器时传递进来的文件类型是MP4,实例的是播放MP4的播放器,调用play方法时调用的应该是palyMp4。

在播放MP4格式的播放器中调用playVlc方法显然是不正确的。

public class MediaAdapter implements MediaPlay{
    AdvanceMediaPlay advanceMediaPlay;
    //根据类型,适配对应对象
    public MediaAdapter(AudioTypeEnum audioTypeEnum) {
        switch (audioTypeEnum) {//根据文件类型,实例化对应类型播放器
        case MP4:advanceMediaPlay = new Mp4Play();
            break;
        case VLC:advanceMediaPlay = new VlcPlay();
            break;
        default:
            try {
                throw new Exception("播放类型异常!");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    //根据类型,适配对应方法
    @Override
    public void paly(AudioTypeEnum audioType, String fileName) {
        switch(audioType) {//根据文件类型调用对应方法
        case MP4:
            advanceMediaPlay.playMp4(fileName);
            break;
        case VLC:
            advanceMediaPlay.playVlc(fileName);
            break;
        default:
            try {
                throw new Exception("播放异常!");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

适配器完成后,我们就在音频播放器中添加上适配器

public class AudioPlay implements MediaPlay{
    private MediaAdapter mediaAdapter;//适配器

    
    public void paly(AudioTypeEnum audioType, String fileName) {
        // TODO Auto-generated method stub
        switch(audioType) {
        case MP3://内置MP3播放器
            System.out.println("play mp3:" + fileName);
            break;
        case MP4://TODO 其他可播放类型,采用适配器播放
        case VLC:
            mediaAdapter = new MediaAdapter(audioType);//实例化适配器,适配器会根据类型实例化对应播放器
            mediaAdapter.paly(audioType, fileName);//播放时,会根据对应播放器调用对应方法。
            break;
        default://TODO 无法播放部分抛出异常
            try {
                throw new Exception("播放异常,格式不支持!");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }    
}

测试添加适配器后的音频播放器

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MediaPlay mediaPlay = new AudioPlay();
        mediaPlay.paly(AudioTypeEnum.MP4, "mmm4");
        mediaPlay.paly(AudioTypeEnum.MP3, "mmm3");
        mediaPlay.paly(AudioTypeEnum.VLC, "fff");
    }

}
运行结果:
play mp4:mmm4 play mp3:mmm3 play vlc:fff

参考资料:

https://www.runoob.com/design-pattern/adapter-pattern.html

https://www.cnblogs.com/V1haoge/p/6479118.html

原文地址:https://www.cnblogs.com/huang-changfan/p/10942225.html