定义
适配器模式(Adapter Pattern)是一种结构型设计模式,它用于将一个类的接口转换成客户端所期望的另一个接口。适配器模式使得原本由于接口不兼容而无法一起工作的类可以协同工作。
适配器模式通过引入一个适配器类,将原始类的接口转换成目标接口,从而使得客户端可以通过目标接口调用原始类的功能。适配器类包装了原始类,并实现了目标接口,同时在方法中调用原始类的相应方法,将客户端的请求转发给原始类。
适配器模式包含以下角色:
目标接口(Target):定义客户端所期望的接口,即客户端通过该接口与适配器进行交互。
原始类(Adaptee):需要被适配的类,它定义了一些功能,但与目标接口不兼容。
适配器(Adapter):将原始类的接口转换成目标接口,它包装了原始类,并实现了目标接口,在方法中调用原始类的功能。
适配器模式的优点
- 可以让原本不兼容的类可以协同工作,提高了代码的复用性。
- 可以将具体的实现细节隐藏在适配器中,对客户端来说是透明的,降低了客户端的复杂度。
- 可以在不修改原始类的情况下进行适配,符合开闭原则。
适配器模式适用于以下场景:
当需要将一个已存在的类与其他类一起使用,但其接口不兼容时,可以使用适配器模式来适配其接口。
当希望在不修改原始类的情况下,对其进行功能增强或改造时,可以使用适配器模式。
总而言之,适配器模式可以将不兼容的接口转换为兼容的接口,以实现不同类之间的协同工作。
示例一:计算面积
假设有一个已有的类 LegacyRectangle,它提供了计算矩形面积的方法 calculateArea():
public class LegacyRectangle {
public int calculateArea() {
// 假设这里是已有类的实现逻辑
return 0;
}
}
现在我们需要一个新的类 Rectangle,它也需要计算矩形的面积,但是它的接口是使用宽度和高度作为参数的 calculateArea(int width, int height) 方法。
我们可以使用适配器模式来将 LegacyRectangle 适配成符合 Rectangle 接口的类。创建一个适配器类 RectangleAdapter:
public class RectangleAdapter implements Rectangle {
private LegacyRectangle legacyRectangle;
public RectangleAdapter(LegacyRectangle legacyRectangle) {
this.legacyRectangle = legacyRectangle;
}
@Override
public int calculateArea(int width, int height) {
// 将新接口的方法转换为调用已有类的方法
// 这里可以根据 width 和 height 进行适当的转换
return legacyRectangle.calculateArea();
}
}
然后定义一个新的接口 Rectangle,它包含了我们需要的方法:
public interface Rectangle {
int calculateArea(int width, int height);
}
现在我们可以使用适配器模式来在 Rectangle 接口上使用 LegacyRectangle 类的功能:
public class Main {
public static void main(String[] args) {
LegacyRectangle legacyRectangle = new LegacyRectangle();
Rectangle rectangle = new RectangleAdapter(legacyRectangle);
int width = 5;
int height = 10;
int area = rectangle.calculateArea(width, height);
System.out.println("矩形的面积:" + area);
}
}
通过适配器模式,我们成功地将已有类 LegacyRectangle 适配成了符合新接口 Rectangle 的类,从而能够在新的上下文中使用。
示例一:播放器
假设我们有一个音频播放器(AudioPlayer)接口,它定义了播放音频文件的方法playAudio()。然而,我们的应用程序中使用了不同类型的音频文件,包括MP3文件、MP4文件和VLC文件,它们的播放方法是不同的。我们希望通过适配器模式,使得音频播放器能够播放这些不同类型的音频文件。
首先,我们定义一个音频播放器接口(AudioPlayer):
public interface AudioPlayer {
void playAudio(String filename);
}
然后,我们实现了MP3播放器(Mp3Player)和MP4播放器(Mp4Player):
public class Mp3Player {
public void playMp3(String filename) {
System.out.println("Playing MP3 file: " + filename);
}
}
public class Mp4Player {
public void playMp4(String filename) {
System.out.println("Playing MP4 file: " + filename);
}
}
接下来,我们定义一个适配器类(MediaAdapter),它实现了音频播放器接口,并且包装了MP3播放器和MP4播放器:
public class MediaAdapter implements AudioPlayer {
private Mp3Player mp3Player;
private Mp4Player mp4Player;
public MediaAdapter() {
mp3Player = new Mp3Player();
mp4Player = new Mp4Player();
}
@Override
public void playAudio(String filename) {
if (filename.endsWith(".mp3")) {
mp3Player.playMp3(filename);
} else if (filename.endsWith(".mp4")) {
mp4Player.playMp4(filename);
} else {
System.out.println("Unsupported audio format");
}
}
}
最后,我们实现一个音频播放器(AudioPlayerImpl),它使用适配器来播放不同类型的音频文件:
public class AudioPlayerImpl implements AudioPlayer {
private MediaAdapter mediaAdapter;
public AudioPlayerImpl() {
mediaAdapter = new MediaAdapter();
}
@Override
public void playAudio(String filename) {
mediaAdapter.playAudio(filename);
}
}
现在,我们可以使用音频播放器来播放不同类型的音频文件,而无需关心其具体的播放逻辑:
public class Main {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayerImpl();
audioPlayer.playAudio("song.mp3"); // 使用适配器播放MP3文件
audioPlayer.playAudio("video.mp4"); // 使用适配器播放MP4文件
audioPlayer.playAudio("audio.wav"); // 不支持的音频格式,输出"Unsupported audio format"
}
}
这个例子中,适配器模式充当了音频播放器和MP3播放器、MP4播放器之间的适配器,使得音频播放器能够播放不同类型的音频文件。