1、角色划分
- Target:目标抽象类
- Adapter:适配器类
- Adaptee:适配者类
- Client:客户类
2、UML类图
3、源码
public class AdaptorPattern {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("rmvb", "far far away.rmvb");
audioPlayer.play("avi", "mind me.avi");
}
}
/**
* 普通的媒体播放器
*/
interface MediaPlayer {
void play(String audioType,String fileName);
}
/**
* 高级的媒体播放器
*/
interface AdvancedMediaPlayer {
void playRmvb(String fileName);
void playAvi(String fileName);
}
/**
* 可以播放rmvb格式的播放器
*/
class RmvbPlayer implements AdvancedMediaPlayer {
public void playRmvb(String fileName) {
System.out.println("Playing rmvb file. Name: " + fileName);
}
public void playAvi(String fileName) {
}
}
/**
* 可以播放avi格式的播放器
*/
class AviPlayer implements AdvancedMediaPlayer {
public void playRmvb(String fileName) {
}
public void playAvi(String fileName) {
System.out.println("Playing avi file. Name: " + fileName);
}
}
/**
* 创建实现了 MediaPlayer 接口的适配器类。
*/
class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMediaPlayer;
public MediaAdapter(String audioType) {
if("RMVB".equalsIgnoreCase(audioType)) {
advancedMediaPlayer = new RmvbPlayer();
} else if("AVI".equalsIgnoreCase(audioType)) {
advancedMediaPlayer = new AviPlayer();
}
}
public void play(String audioType, String fileName) {
if("RMVB".equalsIgnoreCase(audioType)) {
advancedMediaPlayer.playRmvb(fileName);
} else if("AVI".equalsIgnoreCase(audioType)) {
advancedMediaPlayer.playAvi(fileName);
}
}
}
/**
* 创建实现了 MediaPlayer 接口的实体类。
*/
class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
public void play(String audioType, String fileName) {
if("MP4".equalsIgnoreCase(audioType)) {
System.out.println("Playing mp4 file. Name: " + fileName);
} else if("RMVB".equalsIgnoreCase(audioType) || "AVI".equalsIgnoreCase(audioType)) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else{
System.out.println("media is not support");
}
}
}
输出结果
media is not support
Playing mp4 file. Name: alone.mp4
Playing rmvb file. Name: far far away.rmvb
Playing avi file. Name: mind me.avi
3、特点
在类适配器模式中,适配器类实现了目标抽象类接口并继承了适配者类,并在目标抽象类的实现方法中调用所继承的适配者类的方法;在对象适配器模式中,适配器类继承了目标抽象类并定义了一个适配者类的对象实例,在所继承的目标抽象类方法中调用适配者类的相应业务方法
4、优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
5、缺点
对于Java不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
6、jdk中的适配器模式
- InputStreamReader Client
- StreamDecoder Adapter
- InputStream Adaptee
- Reader Target
// 该类为Client类
public class InputStreamReader extends Reader {
// 这里的sd为适配器类
private final StreamDecoder sd;
// 通过构造方法实例化Adapter
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
// target的抽象方法
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
...
}
// 该类为Adapter类
public class StreamDecoder extends Reader {
private InputStream in;
// target的抽象read方法
public int read() throws IOException {
return this.read0();
}
read0方法中最后还是会调用readBytes,完成字节流的读取
// 给inputstreamreader添加可以读取bytes的方法,适配了Adaptee的read方法
private int readBytes() throws IOException {
...
int var4 = this.in.read(this.bb.array(), this.bb.arrayOffset() + var2, var3);
...
}
}
// 该类为Target类
public abstract class Reader implements Readable, Closeable {
// 抽象方法
abstract public int read(char cbuf[], int off, int len) throws IOException;
}
// 该类为Adaptee类
public abstract class InputStream implements Closeable {
// Adaptee的read方法
public int read(byte b[], int off, int len) throws IOException {
...
}
}