IBM 适配器模式详解
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器的特点在于兼容,从代码上的特点来说,适配类与原有的类具有相同的接口,并且持有新的目标对象。就如同一个三孔转2孔的适配器一样,他有三孔的插头,可以插到三孔插座里(适配类与原有的类具有相同的接口),又有两孔的插座可以被2孔插头插入(适配器拥有 被适配对象的引用,可以调用被适配对象的 方法)。适配器模式是在于对原有3孔的改造。在使用适配器模式的时候,我们必须同时持有原对象,适配对象,目标对象。。。。
适配器模式将一个类的接口适配成用户所期待的。一个适配器通常允许因为接口不兼容而不能一起工作的类能够在一起工作,做法是将类自己的接口包裹在一个已存在的类中。
Adapter 设计模式主要目的组合两个不相干类,常用有两种方法,第一种解决方案是修改各自类的接口。但是如果没有源码,或者不愿意为了一个应用而修改各自的接口,则需要使用 Adapter 适配器,在两种接口之间创建一个混合接口。
图 1. 适配器模式类图
图 1 所示是适配器模式的类图。Adapter 适配器设计模式中有 3 个重要角色:被适配者 Adaptee,适配器 Adapter 和目标对象 Target。其中两个现存的想要组合到一起的类分别是被适配者 Adaptee 和目标对象 Target 角色,按照类图所示,我们需要创建一个适配器 Adapter 将其组合在一起。
使用场景:
1.你想使用一个已经存在的类,而它的接口不符合你的需求。
2.你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
3.(仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
通过下面的实例来演示适配器模式的使用。其中,音频播放器设备只能播放 mp3 文件,通过使用一个更高级的音频播放器来播放 vlc 和 mp4 文件。
AudioPlayer 实现了 CommonMediaPlayer 接口,只支持播放 mp3
文件,现有AdvancedMediaPlayer 接口,其实现类有 Mp4Player 和 VlcPlayer ,分别支持播放 mp4和vlc 文件,如何修改使得 CommonMediaPlayer 同时支持 mp3、mp4、vlc文件的播放呢?
思路:
通过一个 适配器 CommonMediaAdapter ,实现CommonMediaPlayer接口,在其内部拥有 AdvancedMediaPlayer 对象属性,当文件类型是 mp4、vlc 时,调用AdvancedMediaPlayer 的实现类对应的方法。在 ImprovedAudioPlayer 内部拥有 CommonMediaAdapter属性,根据不同的文件类型,选择播放mp3(自身功能)还是 mp4、vlc
/**
* 普通媒体播放器接口
*/
public interface CommonMediaPlayer {
void play(String audioType,String fileName);
}
/**
* 音频播放器
*/
public class AudioPlayer implements CommonMediaPlayer {
@Override
public void play(String audioType, String fileName) {
System.out.println("播放音频:" + fileName);
}
}
public interface AdvancedMediaPlayer {
void playMp4(String fileName);
void playVlc(String fileName);
}
public class Mp4Player implements AdvancedMediaPlayer {
@Override
public void playMp4(String fileName) {
System.out.println("Mp4 Player 正在播放: "+fileName);
}
@Override
public void playVlc(String fileName) {
System.out.printf("...");
}
}
public class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playMp4(String fileName) {
System.out.println("...");
}
@Override
public void playVlc(String fileName) {
System.out.println("VLC player 正在播放: "+fileName);
}
}
/**
* CommonMediaPlayer 接口的适配器, 使得CommonMediaAdapter 拥有AdvancedPlayer 的功能
*/
public class CommonMediaAdapter implements CommonMediaPlayer{
private AdvancedMediaPlayer advancedMediaPlayer;
public CommonMediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc")){
advancedMediaPlayer = new VlcPlayer();
}else if (audioType.equalsIgnoreCase("mp4")){
advancedMediaPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMediaPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMediaPlayer.playMp4(fileName);
}
}
}
public class ImprovedAudioPlayer implements CommonMediaPlayer {
private CommonMediaAdapter commonMediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
// 内置功能 已经支持
System.out.println("MP3播放: " + fileName);
} else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
commonMediaAdapter = new CommonMediaAdapter(audioType);
commonMediaAdapter.play(audioType, fileName);
} else {
System.out.println("invalid media. format not supported. ");
}
}
}
测试:
public class AdapterPatternDemo {
public static void main(String[] args) {
CommonMediaPlayer mediaPlayer = new ImprovedAudioPlayer();
mediaPlayer.play("mp3","等一分钟.mp3");
mediaPlayer.play("mp4","等一分钟.mp4");
mediaPlayer.play("vlc","等一分钟.vlc");
}
}
MP3播放: 等一分钟.mp3
Mp4 Player 正在播放: 等一分钟.mp4
VLC player 正在播放: 等一分钟.vlc