设计模式之适配器模式

1 概念定义

适配器模式是一种结构型设计模式,它允许不兼容的接口能够一起工作。适配器作为两个不兼容接口之间的桥梁,将一个类的接口转换成客户端期望的另一个接口。

2 核心思想:

  • 接口转换:将现有类的接口转换为目标接口

  • 复用现有功能:让不兼容的类能够协同工作

  • 透明性:客户端通过目标接口操作,不知道适配器的存在

  • 解耦:将客户端与适配者解耦

3 主要角色:

  • Target(目标接口):客户端期望的接口

  • Adaptee(适配者):需要被适配的已有接口

  • Adapter(适配器):将适配者接口转换为目标接口

  • Client(客户端):通过目标接口与对象交互

两种实现方式:

类适配器:使用多重继承(C++支持)

对象适配器:使用对象组合(推荐方式)

4 应用场景

以多媒体播放器系统为例:

系统原本只支持MP3格式播放

需要集成第三方音频库(支持WAV、FLAC、AAC)

需要集成视频库(支持MP4、AVI、MKV)

各种库的接口完全不同

不能修改现有代码,需要适配不同的媒体格式

5 UML

6 C++ 代码实现

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>
#include <map>
#include <vector>
using namespace std;

// ========== 目标接口:媒体播放器 ==========
class MediaPlayer {
public:
    virtual ~MediaPlayer() = default;
    
    // 播放媒体文件
    virtual void play(const string& filename) = 0;
    
    // 暂停播放
    virtual void pause() = 0;
    
    // 停止播放
    virtual void stop() = 0;
    
    // 获取支持的格式
    virtual vector<string> getSupportedFormats() = 0;
};

// ========== 适配者1:第三方MP3库 ==========
class ThirdPartyMP3Player {
private:
    bool isPlaying;
    string currentFile;
    int volume;
    
public:
    ThirdPartyMP3Player() : isPlaying(false), volume(50) {}
    
    // 第三方库有自己的接口
    void loadMP3File(const string& filePath) {
        cout << "[第三方MP3库] 加载MP3文件: " << filePath << endl;
        currentFile = filePath;
    }
    
    void startPlayback() {
        if (!currentFile.empty()) {
            isPlaying = true;
            cout << "[第三方MP3库] 开始播放: " << currentFile << endl;
        }
    }
    
    void adjustVolume(int level) {
        volume = level;
        cout << "[第三方MP3库] 调整音量到: " << volume << endl;
    }
    
    void pausePlayback() {
        if (isPlaying) {
            isPlaying = false;
            cout << "[第三方MP3库] 暂停播放" << endl;
        }
    }
    
    void stopPlayback() {
        isPlaying = false;
        cout << "[第三方MP3库] 停止播放" << endl;
    }
    
    bool isMP3Supported(const string& filename) {
        return filename.size() > 4 && 
               filename.substr(filename.size() - 4) == ".mp3";
    }
};

// ========== 适配者2:高级音频库(支持多种格式) ==========
class AdvancedAudioLibrary {
private:
    string currentTrack;
    double position;  // 播放位置(秒)
    bool isPaused;
    
public:
    AdvancedAudioLibrary() : position(0), isPaused(false) {}
    
    // 完全不同的接口
    void openMedia(const string& uri) {
        cout << "[高级音频库] 打开媒体: " << uri << endl;
        currentTrack = uri;
    }
    
    void playMedia() {
        if (!currentTrack.empty()) {
            cout << "[高级音频库] 播放媒体,从位置 " << position << "秒开始" << endl;
        }
    }
    
    void pauseMedia() {
        isPaused = true;
        cout << "[高级音频库] 暂停媒体" << endl;
    }
    
    void resumeMedia() {
        if (isPaused) {
            isPaused = false;
            cout << "[高级音频库] 继续播放" << endl;
        }
    }
    
    void stopMedia() {
        position = 0;
        cout << "[高级音频库] 停止播放" << endl;
    }
    
    void seekTo(double seconds) {
        position = seconds;
        cout << "[高级音频库] 跳转到 " << seconds << "秒" << endl;
    }
    
    bool supportsFormat(const string& filename) {
        string ext = filename.substr(filename.find_last_of('.') + 1);
        return ext == "wav" || ext == "flac" || ext == "aac" || ext == "ogg";
    }
};

// ========== 适配者3:视频播放库 ==========
class VideoPlayerLibrary {
private:
    string videoFile;
    bool isFullScreen;
    int brightness;
    
public:
    VideoPlayerLibrary() : isFullScreen(false), brightness(50) {}
    
    // 视频库的独特接口
    void loadVideo(const string& file) {
        cout << "[视频库] 加载视频: " << file << endl;
        videoFile = file;
    }
    
    void renderVideo() {
        if (!videoFile.empty()) {
            cout << "[视频库] 渲染视频,亮度: " << brightness << "%" << endl;
        }
    }
    
    void setFullScreen(bool full) {
        isFullScreen = full;
        cout << "[视频库] " << (full ? "全屏模式" : "窗口模式") << endl;
    }
    
    void setBrightness(int level) {
        brightness = level;
        cout << "[视频库] 设置亮度: " << level << "%" << endl;
    }
    
    void playVideo() {
        cout << "[视频库] 播放视频: " << videoFile << endl;
    }
    
    void pauseVideo() {
        cout << "[视频库] 暂停视频" << endl;
    }
    
    void stopVideo() {
        cout << "[视频库] 停止视频" << endl;
    }
    
    bool supportsVideo(const string& filename) {
        string ext = filename.substr(filename.find_last_of('.') + 1);
        return ext == "mp4" || ext == "avi" || ext == "mkv" || ext == "mov";
    }
};

// ========== 对象适配器:MP3适配器 ==========
class MP3Adapter : public MediaPlayer {
private:
    // 使用对象组合
    ThirdPartyMP3Player* mp3Player;
    bool isPlaying;
    
public:
    MP3Adapter(ThirdPartyMP3Player* player) : mp3Player(player), isPlaying(false) {
        cout << "创建MP3适配器" << endl;
    }
    
    ~MP3Adapter() {
        delete mp3Player;
    }
    
    void play(const string& filename) override {
        // 转换接口调用
        mp3Player->loadMP3File(filename);
        mp3Player->startPlayback();
        mp3Player->adjustVolume(70);  // 设置默认音量
        isPlaying = true;
    }
    
    void pause() override {
        if (isPlaying) {
            mp3Player->pausePlayback();
            isPlaying = false;
        }
    }
    
    void stop() override {
        mp3Player->stopPlayback();
        isPlaying = false;
    }
    
    vector<string> getSupportedFormats() override {
        return {".mp3"};
    }
};

// ========== 对象适配器:高级音频适配器 ==========
class AdvancedAudioAdapter : public MediaPlayer {
private:
    AdvancedAudioLibrary* audioLib;
    bool isPlaying;
    
public:
    AdvancedAudioAdapter(AdvancedAudioLibrary* lib) : audioLib(lib), isPlaying(false) {
        cout << "创建高级音频适配器" << endl;
    }
    
    ~AdvancedAudioAdapter() {
        delete audioLib;
    }
    
    void play(const string& filename) override {
        // 转换接口调用
        audioLib->openMedia(filename);
        audioLib->playMedia();
        isPlaying = true;
    }
    
    void pause() override {
        if (isPlaying) {
            audioLib->pauseMedia();
            isPlaying = false;
        }
    }
    
    void stop() override {
        audioLib->stopMedia();
        isPlaying = false;
    }
    
    vector<string> getSupportedFormats() override {
        return {".wav", ".flac", ".aac", ".ogg"};
    }
};

// ========== 对象适配器:视频适配器 ==========
class VideoAdapter : public MediaPlayer {
private:
    VideoPlayerLibrary* videoLib;
    bool isPlaying;
    
public:
    VideoAdapter(VideoPlayerLibrary* lib) : videoLib(lib), isPlaying(false) {
        cout << "创建视频适配器" << endl;
    }
    
    ~VideoAdapter() {
        delete videoLib;
    }
    
    void play(const string& filename) override {
        // 转换接口调用
        videoLib->loadVideo(filename);
        videoLib->setFullScreen(true);  // 视频默认全屏
        videoLib->setBrightness(60);
        videoLib->playVideo();
        videoLib->renderVideo();
        isPlaying = true;
    }
    
    void pause() override {
        if (isPlaying) {
            videoLib->pauseVideo();
            isPlaying = false;
        }
    }
    
    void stop() override {
        videoLib->stopVideo();
        isPlaying = false;
    }
    
    vector<string> getSupportedFormats() override {
        return {".mp4", ".avi", ".mkv", ".mov"};
    }
};

// ========== 类适配器:使用多重继承(C++特有) ==========
class ClassAdapter : public MediaPlayer, private ThirdPartyMP3Player {
public:
    ClassAdapter() {
        cout << "创建类适配器" << endl;
    }
    
    void play(const string& filename) override {
        // 直接使用父类的方法
        loadMP3File(filename);
        startPlayback();
        adjustVolume(70);
    }
    
    void pause() override {
        pausePlayback();
    }
    
    void stop() override {
        stopPlayback();
    }
    
    vector<string> getSupportedFormats() override {
        return {".mp3"};
    }
};

// ========== 适配器工厂:媒体播放器工厂 ==========
class MediaPlayerFactory {
private:
    map<string, MediaPlayer*> players;
    
public:
    MediaPlayerFactory() {
        // 注册各种适配器
        players[".mp3"] = new MP3Adapter(new ThirdPartyMP3Player());
        players[".wav"] = new AdvancedAudioAdapter(new AdvancedAudioLibrary());
        players[".flac"] = new AdvancedAudioAdapter(new AdvancedAudioLibrary());
        players[".aac"] = new AdvancedAudioAdapter(new AdvancedAudioLibrary());
        players[".ogg"] = new AdvancedAudioAdapter(new AdvancedAudioLibrary());
        players[".mp4"] = new VideoAdapter(new VideoPlayerLibrary());
        players[".avi"] = new VideoAdapter(new VideoPlayerLibrary());
        players[".mkv"] = new VideoAdapter(new VideoPlayerLibrary());
        players[".mov"] = new VideoAdapter(new VideoPlayerLibrary());
    }
    
    ~MediaPlayerFactory() {
        for (auto& pair : players) {
            delete pair.second;
        }
    }
    
    MediaPlayer* getPlayer(const string& filename) {
        string ext = filename.substr(filename.find_last_of('.'));
        auto it = players.find(ext);
        if (it != players.end()) {
            cout << "找到适配器 for " << ext << " 格式" << endl;
            return it->second;
        }
        return nullptr;
    }
    
    void listSupportedFormats() {
        cout << "\n支持的格式:" << endl;
        for (const auto& pair : players) {
            cout << "  " << pair.first;
        }
        cout << endl;
    }
};

// ========== 客户端:媒体播放器应用 ==========
class MediaPlayerApp {
private:
    MediaPlayerFactory& factory;
    MediaPlayer* currentPlayer;
    string currentFile;
    
public:
    MediaPlayerApp(MediaPlayerFactory& f) : factory(f), currentPlayer(nullptr) {}
    
    void playFile(const string& filename) {
        cout << "\n=== 尝试播放文件: " << filename << " ===" << endl;
        
        // 获取对应的播放器
        currentPlayer = factory.getPlayer(filename);
        if (!currentPlayer) {
            cout << "错误: 不支持的文件格式!" << endl;
            return;
        }
        
        currentFile = filename;
        currentPlayer->play(filename);
    }
    
    void pause() {
        if (currentPlayer) {
            cout << "\n暂停播放" << endl;
            currentPlayer->pause();
        }
    }
    
    void stop() {
        if (currentPlayer) {
            cout << "\n停止播放" << endl;
            currentPlayer->stop();
        }
    }
    
    void showSupportedFormats() {
        factory.listSupportedFormats();
    }
};

// ========== 不使用适配器模式的直接调用(对比) ==========
class DirectMediaPlayer {
public:
    // 问题:客户端需要了解所有库的细节
    void playMP3(const string& file, ThirdPartyMP3Player& player) {
        if (player.isMP3Supported(file)) {
            player.loadMP3File(file);
            player.startPlayback();
        }
    }
    
    void playWAV(const string& file, AdvancedAudioLibrary& lib) {
        if (lib.supportsFormat(file)) {
            lib.openMedia(file);
            lib.playMedia();
        }
    }
    
    void playVideo(const string& file, VideoPlayerLibrary& lib) {
        if (lib.supportsVideo(file)) {
            lib.loadVideo(file);
            lib.playVideo();
        }
    }
    
    // 问题:每个新格式都需要新方法
    // 问题:客户端需要管理多个不同的对象
    // 问题:接口不统一,使用复杂
};

// ========== 主函数 ==========
int main() {
    cout << "=== 适配器模式演示:多媒体播放器 ===\n" << endl;
    
    // 创建工厂
    MediaPlayerFactory factory;
    factory.listSupportedFormats();
    
    // 创建播放器应用
    MediaPlayerApp app(factory);
    
    // 播放各种格式的文件
    cout << "\n【场景1:播放MP3】" << endl;
    app.playFile("song.mp3");
    app.pause();
    app.stop();
    
    cout << "\n【场景2:播放FLAC(高级音频)】" << endl;
    app.playFile("concert.flac");
    app.pause();
    app.stop();
    
    cout << "\n【场景3:播放MP4视频】" << endl;
    app.playFile("movie.mp4");
    app.pause();
    app.stop();
    
    cout << "\n【场景4:尝试不支持的格式】" << endl;
    app.playFile("document.pdf");
    
    // 演示类适配器
    cout << "\n=== 类适配器演示 ===" << endl;
    ClassAdapter classAdapter;
    classAdapter.play("song.mp3");
    classAdapter.pause();
    classAdapter.stop();
    
    // 对比:不使用适配器模式的复杂度
    cout << "\n=== 对比:不使用适配器模式 ===" << endl;
    DirectMediaPlayer directPlayer;
    ThirdPartyMP3Player mp3;
    AdvancedAudioLibrary audio;
    VideoPlayerLibrary video;
    
    cout << "\n直接调用需要知道每种库的接口:" << endl;
    directPlayer.playMP3("song.mp3", mp3);
    directPlayer.playWAV("sound.wav", audio);
    directPlayer.playVideo("movie.mp4", video);
    
    return 0;
}

7 总结

不使用适配器模式的坏处

如果不使用适配器模式,可能会采用以下几种实现方式:

方式1:直接修改客户端代码

cpp 复制代码
// 问题:客户端代码需要了解所有库的细节
class MediaApp {
private:
    ThirdPartyMP3Player mp3Player;
    AdvancedAudioLibrary audioLib;
    VideoPlayerLibrary videoLib;
    
public:
    void playFile(const string& filename) {
        string ext = filename.substr(filename.find_last_of('.') + 1);
        
        // 到处都是条件判断
        if (ext == "mp3") {
            // 需要知道MP3库的接口
            if (mp3Player.isMP3Supported(filename)) {
                mp3Player.loadMP3File(filename);
                mp3Player.startPlayback();
            }
        }
        else if (ext == "wav" || ext == "flac" || ext == "aac") {
            // 需要知道高级音频库的接口
            if (audioLib.supportsFormat(filename)) {
                audioLib.openMedia(filename);
                audioLib.playMedia();
            }
        }
        else if (ext == "mp4" || ext == "avi" || ext == "mkv") {
            // 需要知道视频库的接口
            if (videoLib.supportsVideo(filename)) {
                videoLib.loadVideo(filename);
                videoLib.playVideo();
            }
        }
        else {
            cout << "不支持的格式" << endl;
        }
    }
    
    // 问题:添加新格式需要修改这个方法
    // 问题:暂停、停止等操作更难统一处理
};

问题:

  • 客户端与所有第三方库紧耦合

  • 添加新格式需要修改客户端代码

  • 代码重复,每个操作都要写条件判断

  • 违反开闭原则

方式2:为每个格式创建不同的播放器类

cpp 复制代码
// 问题:类爆炸
class MP3FilePlayer {
public:
    void playMP3(const string& file) {
        ThirdPartyMP3Player player;
        player.loadMP3File(file);
        player.startPlayback();
    }
};

class WAVFilePlayer {
public:
    void playWAV(const string& file) {
        AdvancedAudioLibrary lib;
        lib.openMedia(file);
        lib.playMedia();
    }
};

class MP4FilePlayer {
public:
    void playMP4(const string& file) {
        VideoPlayerLibrary lib;
        lib.loadVideo(file);
        lib.playVideo();
    }
};

// 客户端需要知道用哪个类
class Client {
public:
    void play(const string& file, const string& type) {
        if (type == "mp3") {
            MP3FilePlayer().playMP3(file);
        } else if (type == "wav") {
            WAVFilePlayer().playWAV(file);
        }
        // ...
    }
};

问题:

  • 类的数量随着格式增加而增加

  • 接口不统一,客户端需要了解每个类的不同方法

  • 难以实现统一的操作(如暂停所有播放器)

方式3:使用函数指针或回调

cpp 复制代码
// 问题:复杂且容易出错
typedef void (*PlayFunction)(const string&);
typedef void (*PauseFunction)();

map<string, pair<PlayFunction, PauseFunction>> formatHandlers;

void playMP3Handler(const string& file) {
    ThirdPartyMP3Player player;
    player.loadMP3File(file);
    player.startPlayback();
}

void playWAVHandler(const string& file) {
    AdvancedAudioLibrary lib;
    lib.openMedia(file);
    lib.playMedia();
}

// 注册处理器
formatHandlers[".mp3"] = {playMP3Handler, nullptr};
formatHandlers[".wav"] = {playWAVHandler, nullptr};

// 使用
void playFile(const string& file) {
    string ext = file.substr(file.find_last_of('.'));
    auto it = formatHandlers.find(ext);
    if (it != formatHandlers.end()) {
        it->second.first(file);
    }
}

问题:

  • 类型不安全

  • 难以处理有状态的对象

  • 暂停、停止等操作难以统一管理

  • 调试困难

适配器模式的优势

  • 接口统一:为不同的类提供统一的访问接口

  • 解耦:客户端与具体实现解耦

  • 复用现有功能:无需修改现有代码就能使用

  • 开闭原则:添加新功能时无需修改现有代码

  • 灵活性:可以选择对象适配器或类适配器

  • 透明性:客户端不知道适配器的存在

  • 责任单一:适配器只负责接口转换

8. 适配器模式的使用场景

  • 使用第三方库:将第三方库的接口适配为自己的接口

  • 集成旧系统:将旧系统的接口适配到新系统

  • 统一多个类的接口:将多个不同接口统一为一个

  • API版本升级:兼容新旧版本的API

  • 跨平台开发:适配不同平台的API

  • 测试和模拟:为难以测试的类创建适配器

相关推荐
逆境不可逃2 小时前
【从零入门23种设计模式12】结构型之代理模式(Spring AOP + 自定义注解 + 切面的实战)
设计模式·代理模式
电子科技圈2 小时前
IAR扩展嵌入式开发平台,推出面向安全关键型应用的长期支持(LTS)服务
嵌入式硬件·安全·设计模式·软件工程·代码规范·设计规范·代码复审
像少年啦飞驰点、2 小时前
Java策略模式从入门到实战:小白也能看懂的设计模式指南
java·设计模式·策略模式·编程入门·小白教程
程序员Terry2 小时前
别再用 if-else 堆砌代码了!策略模式让你的代码优雅十倍
java·设计模式
JTCC3 小时前
Java 设计模式西游篇 - 第八回:适配器模式通万国 女儿国语言无障碍
python·设计模式·适配器模式
无心水3 小时前
【OpenClaw:实战部署】7、Channel子系统设计:如何优雅接入10+消息渠道?——统一接口+适配器模式实战
适配器模式
逆境不可逃4 小时前
【从零入门23种设计模式17】行为型之中介者模式
java·leetcode·microsoft·设计模式·职场和发展·中介者模式
Anurmy4 小时前
设计模式之抽象工厂
设计模式
蜜獾云4 小时前
设计模式之原型模式:以自己为原型,自己实现自己的对象拷贝逻辑
java·设计模式·原型模式