适配器模式
目录
适配器模式(Adapter Pattern)是作为两个不兼容的接⼝之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独⽴接⼝的功能。 这种模式涉及到⼀个单⼀的类,该类负责加⼊独⽴的或不兼容的接⼝功能。举个例⼦,读卡器是作为内存卡 和笔记本之间的适配器。将内存卡插⼊读卡器,再将读卡器插⼊笔记本,这样就可以通过笔记本来读取内存卡。
1 介绍
意图:将⼀个类的接⼝转换成客户希望的另外⼀个接⼝。适配器模式使得原本由于接⼝不兼容⽽不能⼀起⼯作的那些类可以⼀起⼯作。
主要解决:主要解决在软件系统中,常常要将⼀些“现存的对象”放到新的环境中,⽽新环境要求的接⼝是现对象不能满⾜的。
何时使⽤:
1.系统需要使⽤现有的类,而此类的接⼝不符合系统的需要。
2.想要建⽴⼀个可以重复使⽤的类,⽤于与⼀些彼此之间没有太⼤关联的⼀些类,包括⼀些可能在将来引进的类⼀ 起⼯作,这些源类不⼀定有⼀致的接⼝。
3.通过接⼝转换,将⼀个类插⼊另⼀个类系中(⽐如⽼⻁和⻜禽,现在多了⼀个⻜⻁,在不增加实体的需求下,增加⼀个适配器,在⾥⾯包容⼀个⻁对象,实现⻜的接⼝)。
如何解决:继承或依赖(推荐)。
关键代码:适配器继承或依赖已有的对象,实现想要的⽬标接⼝。
实例:
1.美国电器110V,中国220V,就要有⼀个适配器将110V转化为220V。
2.Java JDK 1.1提供了Enumeration接⼝,⽽在Java JDK 1.2中提供了Iterator接⼝,想要使⽤1.2的JDK,则要将以前系统的Enumeration接⼝转化为Iterator接⼝,这时就需要适配器模式。
3.Java中的JDBC。
4.在Linux上运⾏Windows程序。
优点:
1.可以让任何两个没有关联的类⼀起运⾏。
2.提⾼了类的复⽤。
3.增加了类的透明度。
4.灵活性好。
缺点:
1.过多的使⽤适配器,会让系统⾮常零乱,不易整体进⾏把握。⽐如,明明看到调⽤的是A接⼝,其实内部被适配 成了B接⼝的实现,⼀个系统如果太多出现这种情况,⽆异于⼀场灾难。因此如果不是很有必要,可以不使⽤适配 器,⽽是直接对系统进⾏重构。
2.由于Java⾄多继承⼀个类,所以⾄多只能适配⼀个适配者类,⽽且⽬标类必须是抽象类。 使⽤场景:有动机地修改⼀个正常运⾏的系统的接⼝,这时应该考虑使⽤适配器模式。
注意事项:适配器不是在详细设计时添加的,⽽是解决正在服役的项⽬的问题。
2 实现
我们通过下⾯的实例来演示适配器模式的使⽤。其中,⾳频播放器设备只能播放MP3⽂件,通过使⽤⼀个更⾼级的 ⾳频播放器来播放VLC和MP4⽂件。
我们有⼀个MediaPlayer接⼝和⼀个实现了MediaPlayer接⼝的实体类AudioPlayer。默认情况下,AudioPlayer可 以播放MP3格式的⾳频⽂件。
我们还有另⼀个接⼝AdvancedMediaPlayer和实现了AdvancedMediaPlayer接⼝的实体类。该类可以播放VLC和 MP4格式的⽂件。
我们想要让AudioPlayer播放其他格式的⾳频⽂件。为了实现这个功能,我们需要创建⼀个实现了MediaPlayer接 ⼝的适配器类MediaAdapter,并使⽤AdvancedMediaPlayer对象来播放所需的格式。
AudioPlayer使⽤适配器类MediaAdapter传递所需的⾳频类型,不需要知道能播放所需格式⾳频的实际类。 AdapterPatternDemo类使⽤AudioPlayer类来播放各种格式。
具体实现步骤
1.创建⼀个Java项⽬。
2.为媒体播放器创建MediaPlayer接⼝。
package com.设计模式.适配器模式;
/*
* 媒体播放器的接口
* */
public interface MediaPlayer {
//播放音频文件的方法
void play(String audioType,String fileName);
}
3.为更⾼级的媒体播放器创建AdvancedMediaPlayer接⼝。
package com.设计模式.适配器模式;
/*
* 高级媒体播放器的接口
* */
public interface AdvanceMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
4.创建实现AdvancedMediaPlayer接⼝的实体类VlcPlayer。
package com.设计模式.适配器模式;
/*
* Vlc文件的播放器
* */
public class VlcPlayer implements AdvanceMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("当前正在播放Vlc文件,文件名是:"+fileName);
}
@Override
public void playMp4(String fileName) {
//不关注
}
}
5.创建实现AdvancedMediaPlayer接⼝的实体类Mp4Player。
package com.设计模式.适配器模式;
/*
* Mp4媒体播放器
* */
public class Mp4Player implements AdvanceMediaPlayer{
@Override
public void playVlc(String fileName) {
//不关注
}
@Override
public void playMp4(String fileName) {
System.out.println("当前正在播放Mp4文件,文件的名称是:"+fileName);
}
}
6.创建实现MediaPlayer接⼝的适配器类MediaAdapter。
package com.设计模式.适配器模式;
/*
* 媒体的适配器类
* */
public class MediaAdapter implements MediaPlayer{
//适配器依赖于当前的高级媒体播放器的接口
private AdvanceMediaPlayer advanceMediaPlayer;
//对当前的高级播放器做初始化操作
public MediaAdapter(String audioType){
if (audioType.equalsIgnoreCase("vlc")){
//播放vlc类型的文件
advanceMediaPlayer = new VlcPlayer(); //多态中的向上转型
}else if (audioType.equalsIgnoreCase("mp4")){
//播放mp4类型的文件
advanceMediaPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
//根据当前的文件类型来选择调用哪一个播放器
if (audioType.equalsIgnoreCase("vlc")){
advanceMediaPlayer.playVlc(fileName);
}else if (audioType.equalsIgnoreCase("mp4")){
advanceMediaPlayer.playMp4(fileName);
}
}
}
7.创建实现MediaPlayer接⼝的实体类AudioPlayer。
package com.设计模式.适配器模式;
/*
* 音频文件播放器的类:可以播放Mp3文件,如果传递是mp4和vlc需要调用适配器来进行方法
* */
public class AudioPlayer implements MediaPlayer{
private MediaAdapter mediaAdapter; //高级媒体播放的适配器
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("正在播放mp3文件,文件的名字是:"+fileName);
}else if (audioType.equalsIgnoreCase("mp4")
||audioType.equalsIgnoreCase("vlc")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType,fileName);
}else {
System.out.println("您要播放的文件格式不支持!");
}
}
}
8.使⽤AudioPlayer来播放不同类型的⾳频格式。
package com.设计模式.适配器模式;
public class AdapterPattern {
public static void main(String[] args) {
//只能播放mp3类型的对象
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3","后来");
audioPlayer.play("vlc","gg");
audioPlayer.play("mp4","蜘蛛侠");
audioPlayer.play("avi","遇见");
}
}
9.执⾏程序,输出结果。