[学习][笔记]设计模式(基于C/C++实现)<六>适配器模式

简介: [学习][笔记]设计模式(基于C/C++实现)<六>适配器模式

适配器模式

定义

参考菜鸟教程

适配器模式(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 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

!!! 但是我觉得适配器 可以参考安卓适配器实现

相关文章
|
20小时前
|
设计模式 安全 Java
【JAVA学习之路 | 基础篇】单例设计模式
【JAVA学习之路 | 基础篇】单例设计模式
|
2天前
|
算法 编译器 C语言
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(下)
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL
7 0
|
2天前
|
编译器 C语言 C++
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(上)
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL
6 0
|
2天前
|
编译器 C语言 C++
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)(下)
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)
7 0
|
2天前
|
Java 编译器 C#
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)(上)
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)
16 0
|
6天前
|
设计模式 存储 前端开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
|
8天前
|
设计模式 Java Go
【设计模式】适配器模式怎么理解?
【设计模式】适配器模式怎么理解?
10 1
|
8天前
|
编译器 C++
【C++】继续学习 string类 吧
首先不得不说的是由于历史原因,string的接口多达130多个,简直冗杂… 所以学习过程中,我们只需要选取常用的,好用的来进行使用即可(有种垃圾堆里翻美食的感觉)
10 1
|
8天前
|
算法 安全 程序员
【C++】STL学习之旅——初识STL,认识string类
现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽
18 0
|
8天前
|
存储 安全 测试技术
【C++】string学习 — 手搓string类项目
C++ 的 string 类是 C++ 标准库中提供的一个用于处理字符串的类。它在 C++ 的历史中扮演了重要的角色,为字符串处理提供了更加方便、高效的方法。
19 0
【C++】string学习 — 手搓string类项目