专栏首页Java系列教程Java单体应用 - 架构模式 - 03.设计模式-06.适配器模式
原创

Java单体应用 - 架构模式 - 03.设计模式-06.适配器模式

适配器模式

序号

文内章节

视频

1

-

2

-

请参照如上章节导航进行阅读

1.概述

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。

我们通过下面的实例来演示适配器模式的使用。其中,音频播放器设备只能播放 mp3 文件,通过使用一个更高级的音频播放器来播放 vlcmp4 文件。

意图

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

主要解决

主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。

何时使用

  • 系统需要使用现有的类,而此类的接口不符合系统的需要。
  • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
  • 通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

如何解决

继承或依赖(推荐)。

关键代码

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

应用实例

  • 美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。
  • Java JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。
  • LINUX 上运行 WINDOWS 程序。
  • Java 中的 jdbc

优点

  • 可以让任何两个没有关联的类一起运行。
  • 提高了类的复用。
  • 增加了类的透明度。
  • 灵活性好。

缺点

  • 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如:明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
  • 由于 Java 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

使用场景

有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

注意事项

适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

2.实现

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

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

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

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

步骤 1

为媒体播放器和更高级的媒体播放器创建接口。

MediaPlayer.java,代码如下:

public interface MediaPlayer {
   void play(String audioType, String fileName);
}

AdvancedMediaPlayer.java,代码如下:

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

步骤 2

创建实现了 AdvancedMediaPlayer 接口的实体类。

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

步骤 3

创建实现了 MediaPlayer 接口的适配器类。

MediaAdapter.java,代码如下:

public class MediaAdapter implements MediaPlayer {
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
   }
 
   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

步骤 4

创建实现了 MediaPlayer 接口的实体类。

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

步骤 5

使用 AudioPlayer 来播放不同类型的音频格式。

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

步骤 6

执行程序,输出结果:

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

上一篇:原型模式

下一篇:桥接模式

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java入门 - 面向对象 - 06.接口

    原文地址:http://www.work100.net/training/java-interface.html

    光束云
  • Java DateTimeUtils 工具类

    原文地址:http://www.work100.net/tools/code-java/datetime-utils.html

    光束云
  • Java单体应用 - 架构模式 - 04.实践练习(三层架构+MVC)

    原文地址:http://www.work100.net/training/monolithic-architecture-test.html

    光束云
  • Java设计模式学习笔记—适配器模式

    文章最后“Java设计模式笔记示例代码整合”为本系列代码整合,所有代码均为个人手打并运行测试,不定期更新。本节内容位于其Adapter包(package)中。

    汐楓
  • 适配器模式(Adapter Class/Object)

    qubianzhong
  • 运用适配器模式应对项目中的变化

    作者:张纪刚 链接: http://blog.csdn.net/zhangjg_blog/article/details/18779607 (点击文末阅读原文...

    java达人
  • Android - 接口、MVP 的使用心得

    想象一下,有这么一个场景(需求),两个不同的页面,但是页面的展示 UI 是完全相同的。这时候你会想到,这很简单啊,复用吗。但但但但是,它们的数据格式是完全不相同...

    code_horse
  • 接口配置有效管理(获取配置文件内容3种常见方式)

    问:我们项目现在就是配置在yml中的,但是有很多外部接口,配置文件中看起来很乱,有时候修改还修改错了

    肖哥哥
  • 接口自动化测试的一种方案

    去年,我们进行了项目的拆分,拆分后的各个子系统也都逐步的改成了通过接口进行数据的交换,接口测试也被提上日程。经过一段时间的探索,接口自动化测试方案越来越完善,今...

    归根落叶
  • 数据库每日一练(2017/8/1)

    本期题目: (单选题)1、在视图上不能完成的操作是()? A 更新视图 B 查询 C 在视图上定义新的表 D 在视图上定义新的视图 ---- (单选题)2、按...

    Java学习

扫码关注云+社区

领取腾讯云代金券