当前位置: 首页 > news >正文

C++设计模式之适配器模式(结构型模式)

学习软件设计,向OO高手迈进!
设计模式(Design pattern)是软件开发人员在软件开发过程中面临的一般问题的解决方案。
这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
是前辈大神们留下的软件设计的"招式"或是"套路"。

什么是适配器模式

将一个类的接口变换成客户端所期待的另一种接口, 从而使得原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

它包括类适配器对象适配器,本文针对的是对象适配器。适配器模式让我们在设计时不必再关心现存类接口问题。

在这里插入图片描述

UML类图

在这里插入图片描述

适配器模式中的角色:

  1. 目标(Target):定义一个客户端使用的特定接口。
  2. 客户端(Client):使用目标接口,与和目标接口一致的对象合作。
  3. 被适配者(Adaptee):一个现存需要适配的接口。
  4. 适配器(Adapter):负责将Adaptee的接口转换为Target的接口。适配器是一个具体的类,这是该模式的核心。

Version 1.0

下面我们使用手机充电来讲解该模式:

手机充电需要电源适配器将220V的交流电转化为手机锂电池需要的5V直流电。

一、定义目标类

DC5类:目标类(Target)

class DC5 {
public:
    virtual int output5V() = 0;
};

二、定义被适配者

AC220类:被适配的类(Adaptee)

class AC220 {
public:
    int output220V() {
        int output = 220;
        cout << "Current is AC" << output << "V" << endl;
        return output;
    }
};

三、定义适配器

AdapterDC5类:适配器类(Adapter)

class AdapterDC5 : public DC5 {
public:
    AdapterDC5(AC220 *ac220) : m_ac220(ac220) {}
    int output5V() {
        int output = m_ac220->output220V() / 44;
        cout << "Adapte succeed, current is DC" << output << "V" << endl;
        return output;
    }
private:
    /* have a adaptee */
    AC220 *m_ac220;
};

四、客户端

class Mobile
{
public:
    Mobile(DC5 *dc5) : m_dc5(dc5) {}
    void charging() {
        int output = m_dc5->output5V();
        if(output == 5)
            cout << "Changing" << endl;
        else if(output > 5)
            cout << "Bomb" << endl;
    }
private:
    DC5 *m_dc5;
};

main函数

int main(int argc, char** argv) {
    AC220 *pAC220 = new AC220;
    Mobile *pIphone = new Mobile(new AdapterDC5(pAC220));
    pIphone->charging();
    return 0;
}

执行结果

Current is AC220V
Adapte succeed, current is DC5V
Changing

STL

在 STL 中就用到了适配器模式。STL 实现了一种数据结构,称为双端队列(deque),
支持前后两端的插入与删除。STL 实现栈和队列时,没有从头开始定义它们,而是直接
使用双端队列实现的。这里双端队列就扮演了适配器的角色。队列用到了它的后端插入,
前端删除;而栈用到了它的后端插入,后端删除。

class MyDeque {
public:
    void push_back() {}
    void push_front() {}
    void pop_back() {}
    void pop_front() {}
};

class MyStack {
public:
    void push() {
        md.push_back();
    }
    void pop() {
        md.pop_back();
    }
private:
    MyDeque md;
};

class MyQueue {
public:
    void enQueue() {
        md.push_back();
    }
    void deQueue() {
        md.pop_front();
    }
private:
    MyDeque md;
};

优点

  1. 将目标类和适配器类解耦。
  2. 增加了类的透明性和复用性,将具体的实现封装在适配器类中,对于客户端类来说是透明的,而且
    提高了适配器的复用性。
  3. 灵活性和扩展性都非常好,符合开闭原则。

缺点

  1. 一次最多只能适配一个适配器类,不能同时适配多个适配器。
  2. 适配器类不能为最终类。
  3. 目标抽象类只能为接口,不能为类,其使用有一定的局限性。

适用场合

类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:

  1. 想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
  2. 我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。

以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。

相关文章:

  • 3-面试官:说说线程池的 7 大参数
  • 猿创征文|HCIE-Security Day50:网络攻击介绍
  • 一个基于NetCore开发的前后端分离CMS系统
  • centos7安装docker和docker-compose
  • 子查询与内联结分别应该怎么写?
  • Shell编程之第一讲——基础知识认识
  • Java-基于SSM的校园点餐管理系统
  • WLAN与WiFi各是什么意思有什么区别
  • Linux基础-常见问题 xrandr屏幕操作命令详解
  • Jenkins部署springboot项目至远程服务器
  • 商业化广告--体系学习-- 2 -- 行业蓝图篇 -- 广告产品与商业模式
  • 教程,如何给公众号文章或菜单添加附件?
  • 计算机毕业设计springboot+vue基本微信小程序的外卖点餐平台系统
  • 数学建模学习(99):多目标寻优 非支配排序遗传算法NSGA III
  • 做这么多年程序员了,才把ELK和springboot的日志解决方案弄明白
  • Apache Zeppelin在Apache Trafodion上的可视化
  • js算法-归并排序(merge_sort)
  • LintCode 31. partitionArray 数组划分
  • oschina
  • Python连接Oracle
  • react 代码优化(一) ——事件处理
  • SegmentFault 2015 Top Rank
  • spark本地环境的搭建到运行第一个spark程序
  • 百度地图API标注+时间轴组件
  • 代理模式
  • 关于 Cirru Editor 存储格式
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 聊聊flink的TableFactory
  • 码农张的Bug人生 - 初来乍到
  • 如何设计一个比特币钱包服务
  • 学习JavaScript数据结构与算法 — 树
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 一天一个设计模式之JS实现——适配器模式
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​渐进式Web应用PWA的未来
  • ​人工智能书单(数学基础篇)
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (3)STL算法之搜索
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (Python第六天)文件处理
  • (笔试题)分解质因式
  • (二)Eureka服务搭建,服务注册,服务发现
  • (二)Linux——Linux常用指令
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (九十四)函数和二维数组
  • (转)菜鸟学数据库(三)——存储过程
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET 反射 Reflect
  • @Service注解让spring找到你的Service bean
  • @TableId注解详细介绍 mybaits 实体类主键注解
  • [ C++ ] STL_vector -- 迭代器失效问题