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

news/2024/11/22 10:30:29/

设计模式】如何用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(.adaptersomeClass
)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接口的功能。


http://www.ppmy.cn/news/1549008.html

相关文章

面向未来的智能视觉参考设计与汽车架构,思尔芯提供基于Arm技术的创新方案

引言&#xff1a; 随着科技的飞速发展&#xff0c;智能视觉IoT已成为科技领域的热门话题&#xff0c;为智能家居、智慧城市等领域带来新机遇。然而&#xff0c;物联网市场的碎片化特性对智能视觉芯片设计构成挑战。同时&#xff0c;汽车行业正经历技术驱动的变革&#xff0c;软…

Docker+Nginx | Docker(Nginx) + Docker(fastapi)反向代理

在DockerHub搜 nginx&#xff0c;第一个就是官方镜像库&#xff0c;这里使用1.27.2版本演示 1.下载镜像 docker pull nginx:1.27.2 2.测试运行 docker run --name nginx -p 9090:80 -d nginx:1.27.2 这里绑定了宿主机的9090端口&#xff0c;只要访问宿主机的9090端口&#…

uni-app 界面TabBar中间大图标设置的两种方法

一、前言 最近写基于uni-app 写app项目的时候&#xff0c;底部导航栏 中间有一个固定的大图标&#xff0c;并且没有激活状态。这里记录下实现方案。效果如下&#xff08;党组织这个图标&#xff09;&#xff1a; 方法一&#xff1a;midButton的使用 官方文档&#xff1a;ta…

开源Tacchi 视触觉传感器仿真器,为机器人与物体接触仿真提供高质量的Sim2Real性能!

Tacchi是一个基于Taichi编程语言开发的低计算成本弹性体形变仿真器&#xff0c;由方斌教授团队开发并已开源&#xff0c;为机器人与物体接触仿真提供高质量的Sim2Real性能&#xff01;该仿真器以较低的计算资源消耗来模拟弹性体的物理形变&#xff0c;并生成与真实触觉图像相似…

同态加密技术与应用场景

【1】应用场景 同态加密&#xff08;Homomorphic Encryption, HE&#xff09;是一种加密技术&#xff0c;它允许直接对加密数据进行特定的操作&#xff0c;而不需要先将数据解密。这种特性使得同态加密在保护数据隐私的同时&#xff0c;还能支持数据的处理和分析&#xff0c;因…

Sourcetree登录GitLab账号

1. 在GitLab上创建个人访问令牌 在gitlab中点击右上角的头像图标&#xff0c;选择设置进入 Access Tokens&#xff08;访问令牌&#xff09; 页面填写令牌名称和到期时间&#xff0c;指定Scopes&#xff08;范围&#xff09;。一般选择read_repository和api点击 Create person…

如何在 Microsoft Edge 中设置代理: 快速而简单的方法

你知道在 Microsoft Edge 中设置代理可以大大提升浏览体验吗&#xff1f;无论您是想提高隐私保护、访问受地理位置限制的内容&#xff0c;还是想更高效地浏览网页&#xff0c;代理服务器都能改变一切。 本指南将介绍如何在 Microsoft Edge 中设置代理&#xff0c;解决常见的代…

一文了解钩子函数(Hook Functions)

钩子函数是一种允许在软件执行过程中插入自定义逻辑的机制。它为开发者提供了一种灵活的方式&#xff0c;在某些特定的生命周期阶段或事件发生时&#xff0c;执行用户定义的代码&#xff0c;而无需直接修改框架或系统的核心逻辑。 特性 动态扩展&#xff1a;通过钩子函数&am…