文章目录
适配器模式
定义
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
我们通过下面的实例来演示适配器模式的使用。其中,音频播放器设备只能播放 mp3 文件,通过使用一个更高级的音频播放器来播放 vlc 和 mp4 文件。
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
更多,类似电脑各种适配器,
网卡适配器:使电脑增加电脑本身没有的无线网络功能。
蓝牙适配器:使电脑增加没有的蓝牙功能。
都通过同一Usb接口实现,只需要插入适配器即可。
使用场景
主要解决:
主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时使用:
1、系统需要使用现有的类,而此类的接口不符合系统的需要。
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)
应用实例:
1、美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。
2、JAVA JDK 1.1 提供了Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。
3、在 LINUX 上运行 WINDOWS 程序。
4、JAVA 中的 jdbc。
基本思路
实例
现在有个音频播放器(AudioPlay)只能播放mp3格式,现在我们希望这个音频播放器能播放更多格式vlc或者mp4,现有AdvanceMediaPlayer可以播放vlc,和mp4格式。
//media_player.h #ifndef MEDIAPLAYER_H #define MEDIAPLAYER_H #include <string> class MediaPlayer { public: virtual void play(std::string audioType, std::string fileName){ }; }; #endif // MEDIAPLAYER_H //advance_media_player.h #ifndef ADVANCE_MEDIA_PLAYER_H #define ADVANCE_MEDIA_PLAYER_H #include <string> class AdvancedMediaPlayer{ public: virtual void playVlc(std::string fileName){ }; virtual void playMp4(std::string fileName){ }; }; #endif // ADVANCE_MEDIA_PLAYER_H //media_adapter.h #ifndef MEDIA_ADAPTER_H #define MEDIA_ADAPTER_H #include "advance_media_player.h" #include "media_player.h" #include "vlc_player.h" #include "mp4_player.h" class MediaAdapter :public MediaPlayer { private: AdvancedMediaPlayer* advancedMusicPlayerPtr; public: MediaAdapter(std::string audioType){ if(audioType == ("vlc") ){ advancedMusicPlayerPtr = new VlcPlayer; }else if (audioType == "mp4"){ advancedMusicPlayerPtr = new Mp4Player; } } void play(std::string audioType, std::string fileName) override{ if(audioType == ("vlc") ){ advancedMusicPlayerPtr->playVlc(fileName); }else if (audioType == "mp4"){ advancedMusicPlayerPtr->playMp4(fileName); } } }; #endif // MEDIA_ADAPTER_H //mp4_player.h #ifndef MP4_PLAYER_H #define MP4_PLAYER_H #include "advance_media_player.h" #include <iostream> class Mp4Player :public AdvancedMediaPlayer { public: void playMp4(std::string fileName) override{ std::cout<<"Playing mp4 file. Name:"<<fileName<<std::endl; } void playVlc(std::string fileName) override{ } }; #endif // MP4_PLAYER_H //vlc_player.h #ifndef VLC_PLAYER_H #define VLC_PLAYER_H #include "advance_media_player.h" #include <iostream> class VlcPlayer :public AdvancedMediaPlayer { public: void playMp4(std::string fileName) override{ } void playVlc(std::string fileName) override{ std::cout<<"Playing vlc file. Name:"<<fileName<<std::endl; } }; #endif // VLC_PLAYER_H //audio_player.h #ifndef AUDIO_PLAYER_H #define AUDIO_PLAYER_H #include "media_player.h" #include "media_adapter.h" #include "mp4_player.h" class AudioPlayer :public MediaPlayer { private: MediaAdapter* mediaAdapterPtr; public: void play(std::string audioType, std::string fileName) override{ if(audioType == "vlc" || audioType == "mp4"){ mediaAdapterPtr = new MediaAdapter(audioType); mediaAdapterPtr->play(audioType,fileName); }else if (audioType == "mp3"){ std::cout<<"Playing mp3 file. Name: "<<fileName<<std::endl; }else{ std::cout<<"invalid "<<std::endl; } } }; #endif // AUDIO_PLAYER_H //main,cpp #include <iostream> #include "audio_player.h" using namespace std; int main() { AudioPlayer* audioPlayer = new AudioPlayer(); audioPlayer->play("mp3", "beyond the horizon.mp3"); audioPlayer->play("mp4", "alone.mp4"); audioPlayer->play("vlc", "far far away.vlc"); audioPlayer->play("avi", "mind me.avi"); return 0; } 输出结果: Playing mp3 file. Name: beyond the horizon.mp3 Playing mp4 file. Name:alone.mp4 Playing vlc file. Name:far far away.vlc invalid
总结
demo地址
优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。
缺点: 1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
!!! 但是我觉得适配器 可以参考安卓适配器实现