【设计模式】如何用C++实现适配器模式

【设计模式】如何用C++实现适配器模式

一、问题背景

用到过很多次适配器模式,一直不理解为什么用这种模式,好像这个模式天生就该如此使用。

实际上,我们很多的理念都源于一些简朴的思想,这些思想不一定高深,但是在保证代码质量,实现高内聚低耦合的设计思想上也许有所益处。

解决问题时,本着好读书不求甚解的思想去做,以求采用有效合适的方式合理解决问题,这没有错。

但是前置学习或者事后复盘时,也许应该知其然知其所以然。学习其思想,解构其体系,重构其内涵,让这种简朴的思想经历复杂的过程后,再次回归简朴。

二、什么是适配器模式?

适配器模式是一种结构型设计模式,它能使接口不兼容的对象能够相互合作。简单来说,就是将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。

适配器模式的核心思想就是通过引入一个中间层(适配器类),来解决不同接口之间的不兼容问题,使得它们能够协同工作。这种模式在软件开发中非常常见,尤其是在需要集成不同系统或框架的时候。

适配器模式有两种常见的实现方式:

  1. 类适配器模式: 适配器类继承了原有类和目标接口,通过继承来实现接口转换。
  2. 对象适配器模式: 适配器类持有原有类的实例,通过组合的方式来实现接口转换。

一般情况下使用对象适配器,因为它耦合度更低,更符合面向对象的设计原则。

三、为什么使用适配器模式?

  1. 解决接口不兼容问题: 当你希望使用某个类,但是其接口与其他代码不兼容时,可以使用适配器类。

  2. 兼容旧系统: 适配器模式允许你创建一个中间层类,其可作为代码与遗留类、第三方类或提供怪异接口的类之间的转换器。

  3. 提高代码复用性: 通过适配器,可以将已有的类适配成新的接口,从而在新的系统中重用这些类。

四、实现步骤

有现存接口类AClassBClass,可以定义Adapter去适配这些旧接口以实现新功能,在main函数中调用适配器接口来实现自身功能,而无需关注AClassBClass的具体实现。

假设旧接口AFunc1、AFunc2、BFunc1、BFunc2不能满足用户需求,用户需要的是AFunc和BFunc任意组合后的接口,如果将这个接口放在用户调用层去实现的话,用户需要同时持有和管理A对象和B对象,在对象较少的情况下采用这种方式或许可行。

随着需要管理的对象越来越多,用户实现与底层之间的耦合将会越来越深。牵一发而动全身,任何一个底层的修改都可能导致原先的功能出现异常。

而采用适配器模式,我们将接口对象使用适配器管理,针对用户业务场景划分适配器的类别,仅需少许适配器,就可实现用户需要的所有功能。此时所有适配器都是对应用户场景,方便用户理解并且无需关心底层原始实现。

1. 旧接口类someClass

./someClass/AClass.h

#ifndef SOMECLASS_ACLASS_H
#define SOMECLASS_ACLASS_H
namespace SomeClass
{
    class AClass {
    public:
        AClass();
        ~AClass();
        void AFunc1();
        void AFunc2();
    };
}
#endif

./someClass/AClass.cpp

#include "AClass.h"
#include <iostream>

using namespace SomeClass;

AClass::AClass()
{
    std::cout << "In AClass, construction" << std::endl;
}

AClass::~AClass()
{
    std::cout << "In AClass, destruction" << std::endl;
}

void AClass::AFunc1()
{
    std::cout << "In AClass, Func1" << std::endl;
}

void AClass::AFunc2()
{
    std::cout << "In AClass, Func2" << std::endl;
}

./someClass/BClass.h

#ifndef SOMECLASS_BCLASS_H
#define SOMECLASS_BCLASS_H
namespace SomeClass
{
    class BClass {
    public:
        BClass();
        ~BClass();
        void BFunc1();
        void BFunc2();
    };
}
#endif

./someClass/BClass.cpp

#include "BClass.h"
#include <iostream>

using namespace SomeClass;

BClass::BClass()
{
    std::cout << "In BClass, construction" << std::endl;
}

BClass::~BClass()
{
    std::cout << "In BClass, destruction" << std::endl;
}

void BClass::BFunc1()
{
    std::cout << "In BClass, Func1" << std::endl;
}

void BClass::BFunc2()
{
    std::cout << "In BClass, Func2" << std::endl;
}

2. 对象适配器

./adapter/Adapter.h

#ifndef ADAPTER_H
#define ADAPTER_H
namespace Adapter
{
    class Adapter {
    public:
        virtual void FUNCA1B1() = 0;
        virtual void FUNCA1B2() = 0;
        virtual void FUNCA2B1() = 0;
        virtual void FUNCA2B2() = 0;
    };
}
#endif

./adapter/AdapterImpl.h

#ifndef ADAPTER_IMPL_H
#define ADAPTER_IMPL_H
#include "Adapter.h"
#include "AClass.h"
#include "BClass.h"
namespace Adapter
{
    class AdapterImpl : public Adapter {
    public:
        AdapterImpl();
        ~AdapterImpl();
        void FUNCA1B1() override;
        void FUNCA1B2() override;
        void FUNCA2B1() override;
        void FUNCA2B2() override;
    private:
        SomeClass::AClass m_aClass;
        SomeClass::BClass m_bClass;
    };
}
#endif

./adapter/AdapterImpl.cpp

#include "AdapterImpl.h"
#include <iostream>
using namespace Adapter;
using namespace SomeClass;

AdapterImpl::AdapterImpl()
{
    std::cout << "In AdapterImpl, construction" << std::endl;
}

AdapterImpl::~AdapterImpl()
{
    std::cout << "In AdapterImpl, destruction" << std::endl;
}

void AdapterImpl::FUNCA1B1()
{
    m_aClass.AFunc1();
    m_bClass.BFunc1();
}

void AdapterImpl::FUNCA1B2()
{
    m_aClass.AFunc1();
    m_bClass.BFunc2();
}

void AdapterImpl::FUNCA2B1()
{
    m_aClass.AFunc2();
    m_bClass.BFunc1();
}

void AdapterImpl::FUNCA2B2()
{
    m_aClass.AFunc2();
    m_bClass.BFunc2();
}

3. main函数调用

./main.cpp

#include "Adapter.h"
#include "AdapterImpl.h"
#include <memory>

int main()
{
    std::shared_ptr<Adapter::Adapter> adapter = std::make_shared<Adapter::AdapterImpl>();
    adapter->FUNCA1B1();
    adapter->FUNCA1B2();
    adapter->FUNCA2B1();
    adapter->FUNCA2B2();
    return 0;
}

4. 编写CMakeLists.txt

# 设置项目名称和最低CMake版本
cmake_minimum_required(VERSION 3.10)
set(ProjectName Adapter)
project(${ProjectName})

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

include_directories(
    .
    adapter
    someClass
)

file(GLOB LIB_FILE 
    adapter/*
    someClass/*)

add_executable(${ProjectName}
    main.cpp
    ${LIB_FILE})

此时文件树结构如下:

在这里插入图片描述

5. 编译运行

mkdir build
cd build
cmake ..
make -j12
./Adapter

运行结果如下

In AClass, construction
In BClass, construction
In AdapterImpl, construction
In AClass, Func1
In BClass, Func1
In AClass, Func1
In BClass, Func2
In AClass, Func2
In BClass, Func1
In AClass, Func2
In BClass, Func2
In AdapterImpl, destruction
In BClass, destruction
In AClass, destruction

main函数不感知AClass具体实现的情况下使用Adapter对象适配器,同时持有AClassBClass的实例,实现了组合AClass接口和BClass接口的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/919812.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入探讨 Puppeteer 如何使用 X 和 Y 坐标实现鼠标移动

背景介绍 现代爬虫技术中&#xff0c;模拟人类行为已成为绕过反爬虫系统的关键策略之一。无论是模拟用户点击、滚动&#xff0c;还是鼠标的轨迹移动&#xff0c;都可以为爬虫脚本带来更高的“伪装性”。在众多的自动化工具中&#xff0c;Puppeteer作为一个无头浏览器控制库&am…

ubuntu 16.04 中 VS2019 跨平台开发环境配置

su 是 “switch user” 的缩写&#xff0c;表示从当前用户切换到另一个用户。 sudo 是 “superuser do” 的缩写&#xff0c;意为“以超级用户身份执行”。 apt 是 “Advanced Package Tool” 的缩写&#xff0c;Ubuntu中用于软件包管理的命令行工具。 1、为 root 用户设置密码…

如何保证MySQL与Redis缓存的数据一致性?

文章目录 一、引言二、场景来源三、高并发解决方案1. 先更新缓存&#xff0c;再更新数据库2. 先更新数据库&#xff0c;再更新缓存3. 先删除缓存&#xff0c;再更新数据库4. 先更新数据库&#xff0c;再删除缓存小结 四、拓展方案1. 分布式锁与分布式事务2. 消息队列3. 监听bin…

论文阅读——Intrusion detection systems using longshort‑term memory (LSTM)

一.基本信息 论文名称&#xff1a;Intrusion detection systems using longshort‑term memory (LSTM) 中文翻译&#xff1a;基于长短期记忆(LSTM)的入侵检测系统 DOI&#xff1a;10.1186/s40537-021-00448-4 作者&#xff1a;FatimaEzzahra Laghrissi1* , Samira Douzi2*, Kha…

【网络系统管理】Centos7——配置主从mariadb服务器案例(下半部分)

【网络系统管理】Centos7——配置主从mariadb服务器案例-CSDN博客 接上个文档&#xff0c;我们已经完成了主服务器创建数据库备服务器可以看到 一、在DBMS2查看信息 File&#xff0c;Position这两个字段的数据要记好&#xff0c;等一下需要用到 show master status; 二、在…

Flowable工作流 -> 数据存储 -> 表结构梳理

一 前言 初学工作流&#xff0c;我发现集成SpringBoot之后&#xff0c;工作流的各项操作都比较简单&#xff0c;引擎&#xff0c;工作Service这些&#xff0c;直接自动装配即可。流程的定义&#xff08;部署&#xff09;&#xff0c;流程实例启动&#xff0c;实例任务…

机器翻译基础与模型 之一: 基于RNN的模型

一、机器翻译发展历程 基于规则的-->基于实例的-->基于统计方法的-->基于神经网络的 传统统计机器翻译把词序列看作离散空间里的由多个特征函数描述的点&#xff0c;类似 于 n-gram 语言模型&#xff0c;这类模型对数据稀疏问题非常敏感。神经机器翻译把文字序列表示…

【优选算法篇】分治乾坤,万物归一:在重组中窥见无声的秩序

文章目录 分治专题&#xff08;二&#xff09;&#xff1a;归并排序的核心思想与进阶应用前言、第二章&#xff1a;归并排序的应用与延展2.1 归并排序&#xff08;medium&#xff09;解法&#xff08;归并排序&#xff09;C 代码实现易错点提示时间复杂度和空间复杂度 2.2 数组…

DrugLLM——利用大规模语言模型通过 Few-Shot 生成生物制药小分子

摘要 小分子由于能够与特定的生物靶点结合并调节其功能&#xff0c;因此在药物发现领域发挥着至关重要的作用。根据美国食品和药物管理局&#xff08;FDA&#xff09;过去十年的审批记录&#xff0c;小分子药物占所有获批上市药物的 76%。小分子药物的特点是合成相对容易&…

「一」HarmonyOS端云一体化概要

关于作者 白晓明 宁夏图尔科技有限公司董事长兼CEO、坚果派联合创始人 华为HDE、润和软件HiHope社区专家、鸿蒙KOL、仓颉KOL 华为开发者学堂/51CTO学堂/CSDN学堂认证讲师 开放原子开源基金会2023开源贡献之星 「目录」 「一」HarmonyOS端云一体化概要 「二」体验HarmonyOS端云一…

架构师:使用 Atomix 实现分布式协调服务的技术指南

1、简述 Atomix 是一个强大的分布式协调框架,提供了分布式数据结构、协调工具和一致性协议,帮助开发者实现高可用、强一致性的分布式系统。它构建于 Raft 和 Paxos 等一致性协议之上,支持创建分布式锁、Leader 选举、分布式 Map、消息发布-订阅等功能,常用于微服务架构和分…

根据条件 控制layui的table的toolbar的按钮 显示和不显示

部分代码&#xff1a; <!-----查询条件-----> <input type"date" id"StartDate" onchange"PageList()" /> <input type"date" id"EndDate" onchange"PageList()" /><!-----表格Table-----&…

100.【C语言】数据结构之二叉树的堆实现 上

目录 1.顺序结构 2.示意图 ​编辑 从物理结构还原为逻辑结构的方法 3.父子节点编号的规律 4.顺序存储的前提条件 5.堆的简介 堆的定义 堆的两个重要性质 小根堆和大根堆 6.堆的插入 7.堆的实现及操作堆的函数 堆的结构体定义 堆初始化函数HeapInit 堆插入元素函…

CommonsBeanutils与Shiro发序列化利用的学习

一、前言 前面的学习中&#xff0c;过了一遍cc1-cc7的利用链&#xff0c;在CC2的利用链中&#xff0c;学习了 java.util.PriorityQueue&#xff0c;它在Java中是一个优先队列&#xff0c;队列中每一个元素都有自己的优先级。在反序列化这个对象时&#xff0c;为了保证队列顺序…

OpenGL入门008——环境光在片段着色器中的应用

本节将在片段着色器中应用环境光照(Ambient) 文章目录 一些概念光照模型环境光漫反射镜面反射总结 实战简介dependencieslightShader.vslightShader.fsshader.vsshader.fs utilsCube.hCube.cpp main.cppCMakeLists.txt最终效果 一些概念 光照模型 环境光 概述&#xff1a; 在…

cesium for unity的使用

先聊聊导入 看到这里的因该能够知道&#xff0c;官网以及网上绝大多数的方法都导入不进来&#xff0c;那么解决方法如下: 两个链接&#xff1a;按照顺序依次下载这两个tgz和zip&#xff0c;其中tgz为主要部分&#xff0c;zip为示例工程项目 如果您要查看示例工程项目的话&am…

stm32cubemx+VSCODE+GCC+makefile 开发环境搭建

title: stm32cubemxVSCODEGCCmakefile 开发环境搭建 tags: FreertosHalstm32cubeMx 文章目录 内容往期内容导航第一步准备环境vscode 插件插件配置点灯 内容 往期内容导航 第一步准备环境 STM32CubeMXVSCODEMinGWOpenOcdarm-none-eabi-gcc 然后把上面下载的软件 3 4 5 bin 文…

20241120-Milvus向量数据库快速体验

目录 20241120-Milvus向量数据库快速体验Milvus 向量数据库pymilvus内嵌向量数据库模式设置向量数据库创建 Collections准备数据用向量表示文本插入数据 语义搜索向量搜索带元数据过滤的向量搜索查询通过主键搜索 删除实体加载现有数据删除 Collections了解更多 个人主页: 【⭐…

【Axure高保真原型】3D农业管理大屏可视化案例

今天和大家分享3D农业管理大屏可视化案例的原型模板&#xff0c;里面包括重点指标分析、产量分析、种类分析、分布分析、收入分析和销售分析&#xff0c;具体效果可以点击下方视频观看或打开下方预览地址查看哦 【原型效果】 【Axure高保真原型】3D农业管理大屏可视化案例 【原…

使用 LSTM(长短期记忆网络) 模型对时间序列数据(航空旅客人数数据集)进行预测

代码功能 数据准备 加载数据&#xff1a;从公开的航空旅客人数数据集&#xff08;Airline Passengers Dataset&#xff09;中读取时间序列数据。 对数变换和平稳化&#xff1a;对数据应用 log1p 函数减少趋势和波动&#xff0c;使模型更容易学习规律。 归一化处理&#xff1a;…