文章目录
结构型模式:适配器模式
适配器模式
适配器模式的动机确实是解决两个已有接口之间不兼容的问题,通过引入一个适配器类,将不兼容的接口进行转换,使它们能够协同工作,而无需修改已有的代码(通常是旧接口的代码),从而复用旧接口的功能,使其适应新接口的需求。
假设有一个旧的类 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()
,这是新系统中规定的调用方式。
由于 OldInterface
和 NewInterface
的方法名和调用方式不同,直接在新系统中使用 OldInterface
的对象将导致编译错误或运行时错误,这就是所谓的不兼容的接口。
为了复用旧接口的代码,我们可以通过适配器类 Adapter
将 newRequest()
的调用转换为对 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;
}