1. 什么是适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,核心作用是把一个类的接口转换成客户端期望的另一个接口,让原本接口不兼容的类可以一起工作。
在 C++ 中,适配器模式主要有两种实现方式:
- 对象适配器:通过组合持有被适配对象,在内部调用它的方法。
- 类适配器:通过多重继承同时继承目标接口和被适配类。
日常开发中对象适配器使用更普遍,耦合度更低、更灵活,下面重点介绍这种写法。
2. 适用场景
- 想复用已有类,但它的接口与当前系统要求不一致。
- 需要统一多个不同来源的接口,让业务代码只依赖一套稳定接口。
- 使用的第三方库或遗留代码不方便直接修改。
3. 代码示例
假设系统里已经有一个「旧音频播放器」,支持播放.mp3文件:
#include<iostream>#include<string>// 被适配者:支持 MP3 的旧播放器classOldMp3Player{public:voidplayMp3(conststd::string&fileName){std::cout<<"播放 MP3: "<<fileName<<std::endl;}};现在客户端需要一个统一接口,能播放常见音频格式
// 目标接口:客户端期望的稳定接口classMediaPlayer{public:virtual~MediaPlayer()=default;virtualvoidplay(conststd::string&audioType,conststd::string&fileName)=0;};// 适配器:把不同播放器接口统一成目标接口classMediaAdapter:publicMediaPlayer{public:voidplay(conststd::string&audioType,conststd::string&fileName)override{if(audioType=="mp3"){oldMp3Player_.playMp3(fileName);}else{std::cout<<"暂不支持格式: "<<audioType<<std::endl;}}private:OldMp3Player oldMp3Player_;};最后在客户端中,无需关心底层是旧播放器还是新播放器,只面向MediaPlayer接口编程:
intmain(){MediaAdapter player;player.play("mp3","song.mp3");return0;}运行结果:
播放 MP3: song.mp3代码说明
OldMp3Player是已有的旧实现。MediaPlayer是客户端期望的新接口,业务代码只依赖它。MediaAdapter在内部把统一的play调用转换为具体播放器的调用。
4. 类适配器补充
如果希望通过继承来实现,C++ 可以使用多继承同时继承目标接口和被适配类:
classClassAdapter:publicMediaPlayer,publicOldMp3Player{public:voidplay(conststd::string&audioType,conststd::string&fileName)override{if(audioType=="mp3"){playMp3(fileName);}else{std::cout<<"暂不支持格式: "<<audioType<<std::endl;}}};不过这种方式会让适配器与被适配类产生较强的继承耦合,一般更推荐对象适配器。
5. 小结
- 适配器模式解决的是接口不兼容问题,让旧类无需修改即可接入新系统。
- 对象适配器通过组合实现,灵活且耦合低,是 C++ 中更推荐的写法。
- 核心思路是:目标接口负责定义「客户端要什么」,适配器负责「怎么把旧接口翻译成新接口」。
掌握适配器模式后,再对比装饰器模式、代理模式,会更容易理解它们各自侧重的是「转换接口」「增强功能」还是「控制访问」。