设计模式(6/23) - 适配器模式

56 阅读3分钟

适配器模式

1 概述

  • 适配器模式(Adapter Pattern)是一种结构型设计模式,它将一个类的接口转换成客户希望的另一个接口,使得原本接口不兼容的类可以一起工作。
  • 适配器模式通过在原有接口和目标接口之间创建一个适配器类,实现接口的转换,从而使得客户端可以使用目标接口调用原有接口的方法。

2 优缺点及应用场景

2.1 优点

  • 1)提高了类的复用性:通过适配器可以将现有的类与其他接口兼容,使得现有类可以在更多场景下使用。
  • 2)提高了类的灵活性:通过使用适配器,可以在不修改现有代码的情况下实现新功能。
  • 3)符合开闭原则:通过引入适配器类,可以在不修改现有代码的基础上进行扩展。

2.2 缺点

  • 1)增加了代码的复杂性:引入适配器类会增加系统的复杂度,特别是多个适配器类同时存在时。
  • 2)可能会导致性能开销:由于适配器模式增加了一层间接调用,可能会导致一定的性能开销。

2.3 应用场景

  • 1)接口转换:例如,将 Java JDK 1.1 的 Enumeration 接口转换为 1.2 的 Iterator 接口。
  • 2)已有类的接口不符合需求:当我们想使用一个已经存在的类,但它的接口不符合我们的需求时,可以使用适配器模式。
  • 3)希望复用一些现有的类,但是这些类的接口又与复用环境要求的接口不一致时。
  • 4)构建一个可重用的类库,适配器模式可以帮助我们使类库与其他类库或系统兼容。

3 结构

  • 1)目标接口(Target):定义客户需要的接口。
  • 2)适配者类(Adaptee):定义一个已经存在的接口,这个接口需要适配。
  • 3)适配器类(Adapter):实现目标接口,并通过组合或继承的方式调用适配者类中的方法,从而实现目标接口。

4 实现

4.1 UML 类图

适配器模式.jpg

4.2 代码示例

// 为媒体播放器创建接口
interface MediaPlayer {
  public void play(String audioType, String fileName);
}

// 为更高级的媒体播放器创建接口
interface AdvancedMediaPlayer {
  public void playVlc(String fileName);

  public void playMp4(String fileName);
}

// 创建实现了 AdvancedMediaPlayer 接口的实体类:Vlc 播放器
class VlcPlayer implements AdvancedMediaPlayer {
  @Override
  public void playVlc(String fileName) {
    System.out.println("Playing vlc file. Name: " + fileName);
  }

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

// 创建实现了 AdvancedMediaPlayer 接口的实体类:Mp4 播放器
class Mp4Player implements AdvancedMediaPlayer {
  @Override
  public void playVlc(String fileName) {
    // 什么也不做
  }

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

// 创建实现了 MediaPlayer 接口的适配器类
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);
    }
  }
}

// 创建实现了 MediaPlayer 接口的实体类:音频播放器
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");
    }
  }
}

// 使用示例
public class AdapterPatternDemo {
  public static void main(String[] args) {
    // 使用 AudioPlayer 来播放不同类型的音频格式
    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

5 总结

  • 适配器模式通过在原有接口和目标接口之间创建一个适配器类,实现接口的转换,从而使得原本接口不兼容的类可以一起工作。适配器模式提高了类的复用性和灵活性,符合开闭原则,但也增加了系统的复杂性。适配器模式适用于已有类的接口不符合需求的情况,或希望复用一些现有的类但接口不一致的情况。