5、设计模式结构型之适配器模式

设计模式结构型之适配器模式

 
在我们日常生活中,适配器其实是很常见的,举几个例子吧:

1、苹果手机从 7 版本开始,它的耳机接口和充电接口共用,并且都是方形孔。如果你想使用以前的圆形插孔耳机,就只能通过一个适配器来实现。
2、再比如美国电压采用 110V,而中国采用220 V,此时就需要一个适配器将 110 V 转换成 220 V,否则是无法对国内电子设备进行充电的。
 

通过这个例子我们可以看出,通过适配器我们可以构建出一座“桥梁”去连接两个原本不兼容的接口。而适配器模式正是对适配器的应用,
 

知道了适配器的定义,现在让我们看看如何用代码实现一个适配器吧。
 

现在考虑这样一个例子:

一开始,社会上流行的最多的是 MP3 这种音乐格式,那么由此便构建了 AudioPlayer 这一个实现类用于播放 MP3 格式的文件。就像这样:

class AudioPlayer {

  // ...

  play(fileName) {
    console.log("播放 MP3 音乐:" , fileName)
  }
}

const audioPlayer = new AudioPlayer();
audioPlayer.play("千里之外"); // 播放 MP3 音乐: 千里之外

 
但是随着技术进步,又出现了 VLC 和 MP4 这两种格式的文件。于是又构建了两个对应的实现类用于播放这两种格式的文件。像这样

class VideoVclPlayer {

  // ...

  playVLC(fileName) {
    console.log("播放 VLC 视频:" , fileName);
  }
}

class VideoMp4Player {

  // ...

  playMp4(fileName) {
    console.log("播放 MP4 视频:" , fileName)
  }
}

const vlc = new VideoVclPlayer();
vlc.playVLC("哪吒闹海"); // 播放 VLC 视频: 哪吒闹海
const mp4 = new VideoMp4Player();
mp4.playMp4("大闹天宫"); // 播放 MP4 视频: 大闹天宫

 
这个时候,生产 MP3 的老板着急了,他说我们的产品也要能播放另外两种视频格式的文件,并且要保证原来的播放器功能不能变动,那该如何去实现呢?
 

那么接下来我们就来实现老板的想法吧。

1、首先实现一个视频的适配器

class MediaAdapter {

  // ... 

  play(type, fileName) {
    if (type === "VLC") {
      const vlc = new VideoVclPlayer();
      vlc.playVLC(fileName)
    } else if (type === "MP4") {
      const mp4 = new VideoMp4Player();
      mp4.playMp4(fileName);
    }
  }
}

 
2、通过这个适配器,我们就能在原本的 AudioPlayer 上添加播放另外两种格式的文件。就像这样:

class AudioPlayer extends MediaAdapter {

  constructor() {
    super(); // 这是 ES6 中 class 的内容
  }

  play(type, fileName) {
    if (type === "MP3") {
      console.log("播放 MP3 音乐:" , fileName);
    } else if (type === "VLC" || type === "MP4") {
      super.play(type, fileName); // 调用继承类的方法
    } else {
      console.log("不支持该格式!");
    }
    
  }
}

 
现在让我们尝试使用一下改造后的 AudioPlayer 播放器:

const audioPlayer = new AudioPlayer();

audioPlayer.play("MP3", "千里之外"); // 播放 MP3 音乐: 千里之外
audioPlayer.play("VLC", "哪吒闹海"); // 播放 VLC 视频: 哪吒闹海
audioPlayer.play("MP4", "大闹天宫"); // 播放 MP4 视频: 大闹天宫
audioPlayer.play("JPG", ""); // 不支持该格式!

 
注意,在 AudioPlayer 中,我们仍然维持了原来的播放逻辑不变:

if (type === "MP3") {
  console.log("播放 MP3 音乐:" , fileName);
}

 

也许有人会问,为什么需要单独新增 MediaAdapter 这样一个适配器呢?为什么不直接在 AudioPlayer 中直接添加?
这是因为我们的目的不是为了 AudioPlayer 中添加新的功能,而仅仅是为了它能兼容其他格式,因此使用适配器的方式处理是符合要求的。

 
适配器的概念其实是比较简单的,因此我们也没有对这一模式进行过多的描述。

 
这里对适配器模式做一个简单的小结吧:
1、适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁
2、灵活的修改一个正常运行的系统的接口,该接口已经在项目大量调用,这时应该考虑使用适配器模式。
3、这种模式涉及到一个单一的类该类负责加入独立的或不兼容的接口功能。就像我们上面提到的 MediaAdapter 一样,在 MediaAdapter 中添加了播放视频的能力,把 MediaAdapter 作为兼容的接口。

 
最后,也许有同学会把装饰器模式和适配器模式弄混,这里做一个简单的区别:
装饰器模式是在原先功能的基础上扩展功能,而适配器模式是为了保证原功能的条件下去兼容执行其他功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值