【C++设计模式】结构型模式:适配器模式

文章目录

结构型模式:适配器模式

适配器模式

适配器模式的动机确实是解决两个已有接口之间不兼容的问题,通过引入一个适配器类,将不兼容的接口进行转换,使它们能够协同工作,而无需修改已有的代码(通常是旧接口的代码),从而复用旧接口的功能,使其适应新接口的需求。

假设有一个旧的类 OldInterface,它提供了一个不兼容的接口,而现在有一个新的接口 NewInterface,我们希望将 OldInterface 适配为 NewInterface

cpp 复制代码
#include <iostream>

// 旧接口
class OldInterface {
public:
    virtual void oldRequest() {
        std::cout << "OldInterface: oldRequest\n";
    }
};

// 新接口
class NewInterface {
public:
    virtual void newRequest() {
        std::cout << "NewInterface: newRequest\n";
    }
};

// 适配器类,将 OldInterface 适配为 NewInterface
class Adapter : public NewInterface {
private:
    OldInterface* oldObj;

public:
    Adapter(OldInterface* obj) : oldObj(obj) {}

    void newRequest() override {
        // 在适配器中调用旧接口的方法,实现新接口的功能
        std::cout << "Adapter: calling oldRequest via newRequest\n";
        oldObj->oldRequest();
    }
};

// 客户端代码
int main() {
    OldInterface* oldObj = new OldInterface();
    NewInterface* adapter = new Adapter(oldObj);

    // 使用新接口调用适配器
    adapter->newRequest();

    delete oldObj;
    delete adapter;

    return 0;
}

旧接口 (OldInterface) 提供了一个方法 oldRequest(),这是系统中旧有的调用方式。而新接口 (NewInterface) 则要求使用方法 newRequest(),这是新系统中规定的调用方式。

由于 OldInterfaceNewInterface 的方法名和调用方式不同,直接在新系统中使用 OldInterface 的对象将导致编译错误或运行时错误,这就是所谓的不兼容的接口

为了复用旧接口的代码,我们可以通过适配器类 AdapternewRequest() 的调用转换为对 oldRequest() 的调用。这种方式不仅能够复用旧接口的功能,还能使新系统顺利运行。

应用实例

音频播放器

假设我们有一个音频播放系统,需要支持多种音频格式,但旧的播放器只支持MP3格式。我们可以使用适配器模式来扩展它以支持新的音频格式,如WAV。

cpp 复制代码
#include <iostream>
#include <string>

// 旧的音频播放器接口
class OldAudioPlayer {
public:
    void playMP3(const std::string& fileName) {
        std::cout << "Playing MP3 file: " << fileName << std::endl;
    }
};

// 新的音频播放器接口
class NewAudioPlayer {
public:
    virtual void play(const std::string& fileName) = 0;
};

// 适配器类
class AudioAdapter : public NewAudioPlayer {
private:
    OldAudioPlayer* oldPlayer;

public:
    AudioAdapter(OldAudioPlayer* player) : oldPlayer(player) {}

    void play(const std::string& fileName) override {
        // 假设所有非MP3文件格式都需要适配
        if (fileName.substr(fileName.size() - 4) == ".wav") {
            std::cout << "Adapter: Converting WAV file for playback.\n";
            // 适配的播放方式(实际情况下可能需要实现转换逻辑)
            std::cout << "Playing WAV file: " << fileName << std::endl;
        } else {
            // 直接使用旧播放器播放MP3
            oldPlayer->playMP3(fileName);
        }
    }
};


int main() {
    OldAudioPlayer* oldPlayer = new OldAudioPlayer();
    NewAudioPlayer* audioPlayer = new AudioAdapter(oldPlayer);

    audioPlayer->play("song.mp3");  // 使用旧播放器
    audioPlayer->play("track.wav");  // 使用适配器

    delete oldPlayer;
    delete audioPlayer;

    return 0;
}

日志记录系统

假设你有一个日志记录系统,旧的日志记录类只支持输出到控制台,而新的系统希望将日志记录到文件中。可以通过适配器来实现。

cpp 复制代码
#include <iostream>
#include <fstream>
#include <string>

// 旧的日志记录器
class ConsoleLogger {
public:
    void log(const std::string& message) {
        std::cout << "Log: " << message << std::endl;
    }
};

// 新的日志接口
class Logger {
public:
    virtual void log(const std::string& message) = 0;
};

// 适配器类
class FileLoggerAdapter : public Logger {
private:
    ConsoleLogger* consoleLogger;
    std::ofstream file;

public:
    FileLoggerAdapter(ConsoleLogger* logger) : consoleLogger(logger) {
        file.open("log.txt", std::ios::app);
    }

    void log(const std::string& message) override {
        consoleLogger->log(message); // 先输出到控制台
        file << "Log: " << message << std::endl; // 同时写入文件
    }

    ~FileLoggerAdapter() {
        file.close();
    }
};


int main() {
    ConsoleLogger* consoleLogger = new ConsoleLogger();
    Logger* logger = new FileLoggerAdapter(consoleLogger);

    logger->log("This is a log message."); // 同时输出到控制台和文件

    delete consoleLogger;
    delete logger;

    return 0;
}

电源适配器

假设你需要将220V电源转换为110V电源以供特定设备使用。可以使用适配器模式实现。

cpp 复制代码
#include <iostream>

// 旧的电源接口(220V)
class Power220V {
public:
    void providePower() {
        std::cout << "Providing power at 220V." << std::endl;
    }
};

// 新的电源接口(需要110V)
class Power110V {
public:
    virtual void providePower() = 0;
};

// 适配器类
class PowerAdapter : public Power110V {
private:
    Power220V* power220V;

public:
    PowerAdapter(Power220V* power) : power220V(power) {}

    void providePower() override {
        std::cout << "Adapter: Converting 220V to 110V." << std::endl;
        power220V->providePower(); // 调用旧的提供电源的方法
    }
};


int main() {
    Power220V* power220V = new Power220V();
    Power110V* power110V = new PowerAdapter(power220V);

    power110V->providePower(); // 提供110V电源

    delete power220V;
    delete power110V;

    return 0;
}
相关推荐
别动我齐刘海10 小时前
机器人运动控制学习2——基础进阶
c++·人工智能·神经网络·学习·目标检测·机器学习·机器人
傻啦嘿哟10 小时前
英雄联盟皮肤爬虫:爬取全皮肤价格与特效,做比价工具
java·c++·爬虫
码匠许师傅11 小时前
【C++ 面试真题】24. 聊聊 C++ 的时间日期处理
java·c++·面试
闻道且行之11 小时前
图片处理助手|泊松融合原理 + C++ 工程实现,seamlessClone 三模式一次讲透
数据库·c++·人工智能·opencv
莫浅子12 小时前
day01-USB架构与枚举
c++·单片机·嵌入式驱动
小欣加油13 小时前
leetcode3069 将元素分配到两个数组中I
数据结构·c++·算法·leetcode·职场和发展
不会代码的小猴13 小时前
7. JSON
开发语言·c++·笔记·qt·算法·json
沫璃染墨13 小时前
《Qt从零入门系列(六):信号与槽进阶——从多种连接方式到Lambda表达式》
开发语言·c++·qt·代码规范·设计规范·qt5
小小龙学IT14 小时前
ZeroMQ(libzmq)开源消息库深度解析:brokerless 时代的轻量消息内核
c++·开源
Benny_Tang15 小时前
题解:P10230 [COCI 2023/2024 #4] Lepeze
c++·算法