IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【学习笔记】设计模式-适配器模式(Adapter/Wrapper) -> 正文阅读

[Java知识库]【学习笔记】设计模式-适配器模式(Adapter/Wrapper)

0 设计模式

不了解设计模式的小伙伴可以通过这篇文章了解一下什么是设计模式

https://blog.csdn.net/qq_42874315/article/details/120006447

1 适配器模式

适配器模式又称为包装器和转换器,它与装饰器模式有一些类似,主要的功能是实现接口转换的。

生活中的场景:220V的插头在110V上用不了,这时就需要一个转接头(适配器)。

代码中的场景:Java中想去使用SQLServer,但是Java提供的是JDBC,SQLServer提供的是ODBC,这时在它们之间就需要一个转换器:JDBC-ODBC-Bridge。

在这里插入图片描述

2 实现思路

在这里插入图片描述

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

创建高级媒体接口AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。

创建一个适配器让AudioPlayer可以播放其他媒体,MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。

3 需要的类

  1. 基本实体类的接口

  2. 高级实体类的接口

    要适配的目标

  3. 高级实体类

    实现高级接口

  4. 转换器

    实现基本接口,因为是要将基本转换为高级,所要转换器要实现基本实体类接口,同时需要聚合一个高级实体类

  5. 基本实体类

    实现基本接口,聚合适配器,如果传入的是高级类型的就用适配器去调用

  6. 测试类

4 具体实现

4.1 MediaPlayer(基本实体类的接口)

/**
 * 基本媒体
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:35
 */
public interface MediaPlayer {
    void play(String audioType,String fileName);
}

4.2 AdvancedMediaPlayer(高级实体类的接口)

/**
 * 高级媒体
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:36
 */
public interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

4.3 高级实体类(实现高级接口)

4.3.1 Mp4Player

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:38
 */
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);
    }
}

4.3.2 VlcPlayer

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:38
 */
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) {

    }
}

4.4 MediaAdapter(转换器)

/**
 * 基本媒体的适配器
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:40
 */
public class MediaAdapter implements MediaPlayer {

    private AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if("vlc".equalsIgnoreCase(audioType)){
            advancedMusicPlayer = new VlcPlayer();
        } else if ("mp4".equalsIgnoreCase(audioType)){
            advancedMusicPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if("vlc".equalsIgnoreCase(audioType)){
            advancedMusicPlayer.playVlc(fileName);
        }else if("mp4".equalsIgnoreCase(audioType)){
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

4.5 AudioPlayer(基本实体类,原本只支持播放MP3)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:46
 */
public class AudioPlayer implements MediaPlayer {

    private MediaAdapter mediaAdapter;

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

4.6 测试类

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:53
 */
public class Test {
    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");
    }
}

5 扩展(引入工厂,优化上述实例)

5.1 上述实例中存在的一些问题

  1. 问题1:AdvancedMediaPlayer中有多种方法,对于不需要的实现类来说,必需得实现,空着放在那儿
  2. 问题2:AudioPlayer中如果不是基本的mp3,就不用再进行判断了,直接调用适配器,将原来别的mp4、vlc判断交给适配器,这样AudioPlayer的代码就不用再改变了。(如果不这样做的话,后面再加一种mp5,AudioPlayer代码就得改了)
  3. 问题3:适配器MediaAdapter中,if太多了,应该想办法消灭一些

5.2 解决方案

  1. 问题1:合并AdvancedMediaPlayer中的playVlc()和playMp4(),使用playAdvanced()代替
  2. 问题2:AudioPlayer中只留下一个if和一个else,表示基本和高级
  3. 问题3:修改MediaAdapter的play()中为advancedMusicPlayer.playAdvanced(fileName),将原先的if-else全部去除,MediaAdapter的无参构造中,只保留一个if和一个else,用来判断有没有高级实体类(mp4、vlc),给MediaAdapter中聚合的AdvancedMediaPlayer赋值,采用工厂进行赋值。创建一个生产高级实体类的工厂。

5.3 升级后的实例

5.3.1 未修改:MediaPlayer(基本实体类的接口)

/**
 * 基本媒体
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:35
 */
public interface MediaPlayer {
    void play(String audioType, String fileName);
}

5.3.2 修改:AdvancedMediaPlayer(高级实体类的接口)

/**
 * 高级媒体
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:36
 */
public interface AdvancedMediaPlayer {
    void playAdvanced(String fileName);
}

5.3.3 修改:高级实体类(实现高级接口)

Mp4Player

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:38
 */
public class Mp4Player implements AdvancedMediaPlayer {

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

VlcPlayer

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:38
 */
public class VlcPlayer implements AdvancedMediaPlayer {

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

5.3.4 修改:MediaAdapter(转换器)

/**
 * 基本媒体的适配器
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:40
 */
public class MediaAdapter implements MediaPlayer {

    private AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        // 判断一下工厂中是否有这个高级类型
        if (AdvancedMediaPlayerFactory.advancedMediaFactory.containsKey(audioType)){
            advancedMusicPlayer = AdvancedMediaPlayerFactory.advancedMediaFactory.get(audioType);
        } else {
            System.out.println("Invalid media. " + audioType + " format not supported");
            // 真实的场景中,在这里抛出异常,就不会用空的对象去执行play方法了(就不会造成空指针异常了)
            System.exit(0);
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        advancedMusicPlayer.playAdvanced(fileName);
    }
}

5.3.5 修改:AudioPlayer(基本实体类,原本只支持播放MP3)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:46
 */
public class AudioPlayer implements MediaPlayer {

    private MediaAdapter mediaAdapter;

    @Override
    public void play(String audioType, String fileName) {
        //播放 mp3 音乐文件的内置支持
        if ("mp3".equalsIgnoreCase(audioType)){
            System.out.println("Playing mp3 file. Name: "+ fileName);
        }else {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType,fileName);
        }
    }
}

5.3.6 新增:创造高级实体类的工厂

/**
 * 创造高级实体类的工厂
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 18:25
 */
public class AdvancedMediaPlayerFactory {
    public static Map<String,AdvancedMediaPlayer> advancedMediaFactory = new HashMap<>();

    public static AdvancedMediaPlayer getAdvancedMediaFactory(String advancedMediaType){
        return advancedMediaFactory.get(advancedMediaType);
    }

    public static void registerAdvancedMedia(String advancedMediaType,AdvancedMediaPlayer advancedMediaPlayer){
        // 这里最好先判断一下advancedMediaType和advancedMediaPlayer是否为空或""再进行put
        advancedMediaFactory.put(advancedMediaType,advancedMediaPlayer);
    }
}

5.3.7 测试类

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/21 17:53
 */
public class Test {
    public static void main(String[] args) {
        // 这里模拟Springboot启动后自动注册高级对象到工厂map的操作
        // springboot场景中,可以让AdvancedMediaPlayer接口去继承InitializingBean
        // 这样子类都必须要实现一个方法afterPropertiesSet(),这个方法实在程序之后的时候,默认要执行一次的方法,在这里可以进行一下的注册操作
        // 详见项目:24-eliminate-if-else  文章:利用设计模式优雅的干掉if-else
        AdvancedMediaPlayerFactory.registerAdvancedMedia("mp4",new Mp4Player());
        AdvancedMediaPlayerFactory.registerAdvancedMedia("vlc",new VlcPlayer());

        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");
    }
}

6 思维导图

在这里插入图片描述

7 示例源码地址

https://github.com/ChenJiahao0205/design-pattern/tree/master

最后

我是通过马士兵老师的视频和菜鸟教程学习的,部分内容可能会有雷同

想阅读更多设计模式相关文章,欢迎到我的专栏【设计模式学习笔记】、【设计模式】中去查看

在23篇设计模式文章发布完成之后,我会公开完整的思维导图,点关注,不迷路

感谢大家看到这里,文章如有不足,欢迎大家指出;彦祖点个赞吧彦祖点个赞吧彦祖点个赞吧,欢迎关注程序员五条

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-24 10:24:23  更:2021-09-24 10:26:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:32:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码