(6).适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的类协同工作。通过创建一个适配器类,将一个类的接口转换成客户端所期望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式的基本结构
- Target: 定义客户端使用的接口。
- Adaptee: 需要适配的现有类,它有一个与Target不兼容的接口。
- Adapter: 将Adaptee的接口转换成Target接口,使它们能够协同工作。
- Client: 使用Target接口的客户端代码。
示例场景
假设我们有一个现有的
AudioPlayer类,它可以播放MP3格式的音频文件。但现在我们需要让它支持其他格式的音频文件(如VLC支持的格式),而不需要修改AudioPlayer类本身。我们可以使用适配器模式来实现这一点。示例代码
1. Target 接口
// 定义客户端使用的接口
public interface IAdvancedMediaPlayer
{
void PlayVlc(string fileName);
void PlayMp4(string fileName);
}
2. Adaptee 类
// 现有的类,具有与Target不兼容的接口
public class VlcPlayer : IAdvancedMediaPlayer
{
public void PlayVlc(string fileName)
{
Console.WriteLine($"Playing VLC file: {fileName}");
}
public void PlayMp4(string fileName)
{
// 不支持MP4
throw new NotImplementedException();
}
}
public class Mp4Player : IAdvancedMediaPlayer
{
public void PlayVlc(string fileName)
{
// 不支持VLC
throw new NotImplementedException();
}
public void PlayMp4(string fileName)
{
Console.WriteLine($"Playing MP4 file: {fileName}");
}
}
3. Adapter 类
// 适配器类,将Adaptee的接口转换为Target接口
public class MediaAdapter : IMediaPlayer
{
private IAdvancedMediaPlayer _advancedMusicPlayer;
public MediaAdapter(string audioType)
{
if (audioType.Equals("vlc", StringComparison.OrdinalIgnoreCase))
{
_advancedMusicPlayer = new VlcPlayer();
}
else if (audioType.Equals("mp4", StringComparison.OrdinalIgnoreCase))
{
_advancedMusicPlayer = new Mp4Player();
}
}
public void Play(string audioType, string fileName)
{
if (audioType.Equals("vlc", StringComparison.OrdinalIgnoreCase))
{
_advancedMusicPlayer.PlayVlc(fileName);
}
else if (audioType.Equals("mp4", StringComparison.OrdinalIgnoreCase))
{
_advancedMusicPlayer.PlayMp4(fileName);
}
}
}
4. Target 接口
// 定义客户端使用的接口
public interface IMediaPlayer
{
void Play(string audioType, string fileName);
}
5. Client 类
// 使用适配器的客户端代码
public class AudioPlayer : IMediaPlayer
{
private MediaAdapter _mediaAdapter;
public void Play(string audioType, string fileName)
{
// 内置支持的音频类型
if (audioType.Equals("mp3", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine($"Playing MP3 file: {fileName}");
}
// 其他音频类型需要适配器
else if (audioType.Equals("vlc", StringComparison.OrdinalIgnoreCase) || audioType.Equals("mp4", StringComparison.OrdinalIgnoreCase))
{
_mediaAdapter = new MediaAdapter(audioType);
_mediaAdapter.Play(audioType, fileName);
}
else
{
Console.WriteLine($"Invalid media format: {audioType}");
}
}
}
6. 测试代码
class Program
{
static void Main(string[] args)
{
IMediaPlayer audioPlayer = new AudioPlayer();
// 播放MP3文件
audioPlayer.Play("mp3", "beyond_the_horizon.mp3");
// 播放VLC文件
audioPlayer.Play("vlc", "forest.vlc");
// 播放MP4文件
audioPlayer.Play("mp4", "alone.mp4");
// 尝试播放不支持的格式
audioPlayer.Play("avi", "movie.avi");
}
}
输出结果
Playing MP3 file: beyond_the_horizon.mp3
Playing VLC file: forest.vlc
Playing MP4 file: alone.mp4
Invalid media format: avi
详细说明
-
IMediaPlayer 接口:
- 定义了客户端使用的接口,允许播放不同类型的音频文件。
-
AudioPlayer 类:
- 这是客户端使用的类,支持播放MP3文件,并通过适配器支持其他类型的音频文件。
-
IAdvancedMediaPlayer 接口:
- 定义了高级媒体播放器的接口,支持播放VLC和MP4文件。
-
VlcPlayer 和 Mp4Player 类:
- 这些是现有的类,具有与
IMediaPlayer不兼容的接口。
- 这些是现有的类,具有与
-
MediaAdapter 类:
- 这是适配器类,将
VlcPlayer和Mp4Player的接口转换为IMediaPlayer接口。
- 这是适配器类,将
-
客户端代码:
- 客户端代码通过
AudioPlayer类播放不同类型的音频文件,而无需关心具体的实现细节。
- 客户端代码通过
适配器模式的优点
- 提高复用性:通过适配器,可以重用现有的类,而不需要修改它们的代码。
- 开闭原则:可以在不修改现有代码的情况下,引入新的适配器来支持新的功能。
- 简化接口:将复杂的接口转换为简单的接口,使得客户端代码更容易使用。
适配器模式的缺点
- 增加复杂性:引入适配器类可能会增加系统的复杂性。
- 性能开销:适配器可能会影响性能,尤其是在需要频繁转换的情况下。
总结
适配器模式适用于以下场景:
- 需要使用一些已经存在的类,但其接口不符合当前的需求。
- 希望创建一个可以复用的类,该类可以与其他不兼容的类或接口一起工作。
- 需要在系统中动态地添加对新功能的支持,而不修改现有代码。

浙公网安备 33010602011771号