设计模式之适配器模式

设计模式之适配器模式

  适配器模式,既可以作为类结构型模式,也可以作为对象结构型模式。

  定义:将一个类的接口变换成客户端所期待的另一种接口,从而使得原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

  问题描述:在软件开发过程中,有时候会改变应用环境,常常需要将一些现存的对象放在新环境中应用,但是新环境要求的接口是这些现存对象所不满足的,那么如何应对这种问题呢?如何既能利用现有的对象,又能够满足新的应用环境所要求的接口呢?

  解决方案:可以通过继承或者依赖已有的对象,实现想要的目标接口,将一个类插入到另一个类系中,让两个类可以一起工作。

  结构图

设计模式之适配器模式

  举个栗子:现有一个MP3播放器的功能,有一个媒体播放器类MediaPlayer,它实现了接口Player,可以播放mp3格式的音频文件。还有一个媒体播放器类AdvancedMediaPlayer,它实现了接口AdvancedPlayer,可以播放vlc和mp4格式的文件。如今我们要想实现既能播放mp3格式的音频文件,又能播放avi和mp4格式文件的功能,就要将类MediaPlayer和类AdvancedMediaPlayer放在一起工作,然而这两个类所依赖的接口不一致,实现起来比较麻烦,于是适配器模式就可以在这起到作用了,我们创建一个通用的播放器类UniversalMediaPlayer来播放上述三种格式的文件,再创建一个实现了Player接口的适配器类MediaAdapter,在这个适配器中包装一个AdvancedMediaPlayer对象,让它来负责播放所需格式的文件。具体实现方式如下:

  1. 现有的MP3播放器功能,有一个实现了接口Player的媒体播放器类MediaPlayer。代码如下:

      设计模式之适配器模式

         设计模式之适配器模式

  2. 在类AdapterFragment中通过MediaPlayer对象调用play()方法,即可实现播放MP3文件的功能。代码和实现效果如下:

         设计模式之适配器模式

         设计模式之适配器模式

  3. 有另外一个实现了接口AdvancedPlayer的媒体播放器类AdvancedMediaPlayer,它可以播放avi和mp4格式的文件。代码如下:

         设计模式之适配器模式

         设计模式之适配器模式

  4. 同样,在类AdapterFragment中通过AdvancedMediaPlayer对象调用相应的方法,即可实现播放avi和mp4格式文件的功能。代码和实现效果如下:

        设计模式之适配器模式

        设计模式之适配器模式

  5. 现在我们要想实现既能播放mp3格式的音频文件,又能播放avi和mp4格式文件的功能,就要将类MediaPlayer和类AdvancedMediaPlayer放在一起工作了。我们需要一个实现了Player接口的适配器类MediaAdapter,在这个适配器中包装一个AdvancedMediaPlayer对象,让它来负责播放所需格式(avi和mp4)的文件。代码如下:

        设计模式之适配器模式

        设计模式之适配器模式

  6. 再创建一个实现了接口Player的通用的播放器类UniversalMediaPlayer,通过适配器MediaAdapter对象来调用play()方法实现播放上述三种格式的文件的功能。代码如下:

       设计模式之适配器模式

  7. 运行后的效果,如下所示:

   设计模式之适配器模式

  以上,我们就通过类适配器的方式实现了一个通用的播放器功能,并将播放器的使用和实现分离,进行了解耦。

  优点

  1. 将目标类和适配者类进行了解耦,通过引入一个适配器来重用现有的适配者类,无需修改原有的结构;

  2. 增加了类的透明性和复用性。具体的业务逻辑在适配者类中进行,对于客户端类是透明的;有了适配器,适配者类可以在多个不同的类中复用,提高了适配者类的复用性。

  3. 增加系统的灵活性和扩展性。因为适配器是独立存在的,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,符合开闭原则。

  缺点:类适配器模式中的目标抽象类只能为接口,不能为类,使用有一定的局限性。

  适用场景

  1. 需要使用一些现有的类,而这些类的接口(方法名)不符合系统的需要;

  2. 要创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的类一起工作。

  注:对象适配器暂无。