结构型设计模式之适配器模式【设计模式系列】

系列文章目录

C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程
设计模式系列

期待你的关注哦!!!
在这里插入图片描述

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

结构型设计模式之适配器模式

  • 系列文章目录
  • 一、适配器模式介绍
  • 二、桥接模式优缺点
    • 2.1 优点
    • 2.2 缺点
  • 三、桥接模式使用场景
  • 四、桥接模式实现

一、适配器模式介绍

⚠️ 意图:
适配器模式是用来做适配的,它将不兼容的接口转换可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。

⚠️ 主要解决:
主要解决软件系统中,常常要将一些“现存的对象”放到新的环境中,而新的环境要求接口是现对象不能满足的。

⚠️ 何时使用:
(1)系统需要现有的类,而此类的接口不符合系统的需要。
(2)想要建一个可以重复使用的类,用于一些与彼此之间没有太大关联的一些类,包括一些将来引进的类一起工作,这些源类不一定有一致的接口。
(3)通过接口转换,将一个类插入另一个类系中。

⚠️ 如何解决:
继承或依赖(推荐)。

适配器模式是用来做适配的,它将不兼容的接口转换可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。对于这个模式,我们常那USB转接头这样一个形象的例子来解释它。USB转接头充当适配器,通过转接,把两种不兼容的接口变得可以一起工作了。

适配器模式有两种实现方式

  • 类适配器:类适配器通过使用继承关系来实现。
  • 对象适配器:符合组合复用原则,并且使用委托机制,对象适配器使用组合关系来实现。

在这里插入图片描述

图1_1 适配器模式类图

系统的数据和行为都正确,但接口不符时,我们应该考虑使用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。

想使用一个已经存在的类,但如果它的接口,也就是它的方法和你的要求不相同时,就应该考虑用适配器模式。

比如购买的第三方开发组件,该组件接口与我们自己系统的接口不相同,或者由于某种原因无法直接调用该组件,可以考虑适配器。

二、桥接模式优缺点

2.1 优点

  • 能提高类的透明性和复用,现有的类复用但不需要改变;

  • 解决了现有类和目标类不匹配的问题;

  • 目标类和适配器类解耦,提高程序扩展性;

  • 我们可以使用适配器模式开发自己的功能;

  • 符合开闭原则;

  • 具体的实现都在适配器中,客户端知道的只有适配器类,扩展的话,我们只需要扩展适配器就可以,而原有的类是不需要变化的。

2.2 缺点

  • 适配器编写过程中需要全面考虑,可能会增加系统的复杂性

  • 增加系统代码可读的难度

  • 如果过多的使用适配器,会让我们的系统非常凌乱,不易整理和进行把握。比如,我们调用第一个接口,其实内部已经被适配成了调用第二个接口的实现,这种情况在读代码的时候就很容易蒙圈,所以说增加了系统代码的可读的难度。

三、桥接模式使用场景

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

  • 封装有缺陷的接口设计;

  • 统一多类的接口设计;

  • 替换依赖的外部系统;

  • 兼容老版本接口;

  • 适配不同格式的数据。

四、桥接模式实现

Adapter.h

#ifndef ADAPTER_ADAPTER_H
#define ADAPTER_ADAPTER_H

#include <iostream>

//目标接口类,客户需要的接口
class Target
{
public:
    Target();
    virtual ~Target();
    virtual void Request();//定义标准接口
};

//需要适配的类
class Adaptee
{
public:
    Adaptee();
    ~Adaptee();
    static void SpecificRequest();
};

//类模式,适配器类,通过public继承获得接口继承的效果,通过private继承获得实现继承的效果
class Adapter:public Target,private Adaptee
{
public:
    Adapter();
    ~Adapter() override;
    void Request() override;//实现Target定义的Request接口
};

//对象模式,适配器类,继承Target类,采用组合的方式实现Adaptee的复用
class Adapter1:public Target {
public:
    explicit Adapter1(Adaptee *adaptee);

    Adapter1();

    ~Adapter1() override;

    void Request() override;//实现Target定义的Request接口
private:
    Adaptee *_adaptee;

};
#endif //ADAPTER_ADAPTER_H

Adapter.cpp

#include "Adapter.h"

using namespace std;

Target::Target() = default;

Target::~Target() = default;

void Target::Request()
{
    cout << "Target::Request()" << endl;
}

Adaptee::Adaptee() = default;

Adaptee::~Adaptee() = default;

void Adaptee::SpecificRequest()
{
    cout << "Adaptee::SpecificRequest()" << endl;
}

//类模式的Adapter
Adapter::Adapter() = default;

Adapter::~Adapter() = default;

void Adapter::Request()
{
    cout << "Adapter::Request()" << endl;
    this->SpecificRequest();
    cout << "----------------------------" <<endl;
}

//对象模式的Adapter
Adapter1::Adapter1():_adaptee(new Adaptee)
{
}

Adapter1::Adapter1(Adaptee* _adaptee)
{
    this->_adaptee = _adaptee;
}

Adapter1::~Adapter1() = default;

void Adapter1::Request()
{
    cout << "Adapter1::Request()" << endl;
    this->_adaptee->SpecificRequest();
    cout << "----------------------------" <<endl;
}

main.cpp

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

int main() {

    //类模式Adapter
    Target* pTarget = new Adapter();
    pTarget->Request();

    //对象模式Adapter1
    Adaptee* ade = new Adaptee();
    Target* pTarget1= new Adapter1(ade);
    pTarget1->Request();

    //对象模式Adapter2
    Target* Target2 = new Adapter1();
    Target2->Request();

    return 0;
}

在Adapter模式的两种模式中,有一个很重要的概念就是接口继承和实现继承的区别和联系。接口继承和实现继承是面向对象领域的两个重要的概念,接口继承指的是通过继承,子类获得了父类的接口,而实现继承指的是通过继承子类获得了父类的实现(并不统共接口)。在C++中的public继承既是接口继承又是实现继承,因为子类在继承了父类后既可以对外提供父类中的接口操作,又可以获得父类的接口实现。当然我们可以通过一定的方式和技术模拟单独的接口继承和实现继承,例如我们可以通过private继承获得实现继承的效果(private继承后,父类中的接口都变为private,当然只能是实现继承了。),通过纯抽象基类模拟接口继承的效果,但是在C++中pure virtual function也可以提供默认实现,因此这是不纯正的接口继承,但是在Java中我们可以interface来获得真正的接口继承了。

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

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

相关文章

【Hadoop 01】简介

目录 1 Hadoop 简介 2 下载并配置Hadoop 2.1 修改/etc/profile 2.2 修改hadoop-env.sh 2.3 修改core-site.xml 2.4 修改hdfs-site.xml 2.5 修改mapred-site.xml 2.6 修改yarn-site.xml 2.7 修改workers 2.8 修改start-dfs.sh、stop-dfs.sh 2.9 修改start-yarn.sh、s…

【VUE】解决图片视频加载缓慢/首屏加载白屏的问题

1 问题描述 在 Vue3 项目中&#xff0c;有时候会出现图片视频加载缓慢、首屏加载白屏的问题 2 原因分析 通常是由以下原因导致的&#xff1a; 图片或视频格式不当&#xff1a;如果图片或视频格式选择不当&#xff0c;比如选择了无损压缩格式&#xff0c;可能会导致文件大小过大…

MySQL(一)基本架构、SQL语句操作、试图

MySQL系列文章 MySQL&#xff08;一&#xff09;基本架构、SQL语句操作、试图 MySQL&#xff08;二&#xff09;索引原理以及优化 MySQL&#xff08;三&#xff09;SQL优化、Buffer pool、Change buffer MySQL&#xff08;四&#xff09;事务原理及分析 MySQL&#xff08;五&a…

清洁机器人规划控制方案

清洁机器人规划控制方案 作者联系方式Forrest709335543qq.com 文章目录 清洁机器人规划控制方案方案简介方案设计模块链路坐标变换算法框架 功能设计定点自主导航固定路线清洁区域覆盖清洁贴边沿墙清洁自主返航回充 仿真测试仿真测试准备定点自主导航测试固定路线清洁测试区域…

SpringBoot项目的创建

等待maven下载完成 删除无用文件 此时我们就创建成功了

在外远程NAS群晖Drive - 群晖Drive挂载电脑磁盘同步备份【无需公网IP】

文章目录 前言1.群晖Synology Drive套件的安装1.1 安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用 2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用 3. 结语 前言 群晖作为专业的数据存储中心&…

Windows11的VS201x编译OpenCV+Contrib+CUDA

(1) CUDA下载&#xff0c;注意要和cudnn版本号相关。 我安装的是cuda11.0,注意VS2015不能编译CUDA11&#xff0c;所以用VS2015的话需要下载CUDA 10。因为更高的版本目前还没有cudnn。 (2) 下载和安装VS2015。 (3) 下载和解压CMake。 CMake地址&#xff1a; Releases Kitw…

Linux中docker的基本操作

文章目录 一、docker概述1.1 什么是docker1.2 Docker与虚拟机的特性区别1.3 容器在内核中支持2种重要技术1.4 docker的核心概念 二、安装docker三、Docker 镜像操作四、Docker 容器操作 一、docker概述 1.1 什么是docker 是一个开源的应用容器引擎&#xff0c;基于go语言开发…

js 在浏览器窗口关闭后还可以不中断网络请求

有个需求&#xff0c;我们需要在用户发送数据过程中&#xff0c;如果用户关闭了网页(包括整个浏览器关闭)&#xff0c;不要中断数据传递 目前XMLHttpRequest对象是不支持的 http服务器 为了测试效果我们用nodejs写了个http服务器代码 文件名为httpServer.js如下&#xff0c;…

基于深度学习淡水鱼体重智能识别模型研究

工作原理为&#xff1a;首先对大众淡水鱼图片进行数据清洗并做标签分类&#xff0c;之后基于残差网络ResNet50模型进行有监督的分类识别训练&#xff0c;获取识别模型。其次通过搭建回归模型设计出体重模型&#xff0c;对每一类淡水鱼分别拟合出对应的回归方程&#xff0c;将获…

Transformer 模型实用介绍:BERT

动动发财的小手&#xff0c;点个赞吧&#xff01; 在 NLP 中&#xff0c;Transformer 模型架构是一场革命&#xff0c;极大地增强了理解和生成文本信息的能力。 在本教程[1]中&#xff0c;我们将深入研究 BERT&#xff08;一种著名的基于 Transformer 的模型&#xff09;&#…

Jmeter 如何并发执行 Python 脚本

目录 1. 前言 2. Python 实现文件上传 3. Jmeter 并发执行 4. 最后 1. 前言 JMeter 是一个开源性能测试工具&#xff0c;它可以帮助我们更轻松地执行性能测试&#xff0c;并使测试结果更加可靠。Python 是一种广泛使用的编程语言&#xff0c;它可以用于开发各种软件和应用…

017-从零搭建微服务-系统服务(四)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…

数学建模入门-如何从0开始,掌握数学建模的基本技能

一、前言 本文主要面向没有了解过数学建模的同学&#xff0c;帮助同学们如何快速地进行数学建模的入门并且尽快地在各类赛事中获奖&#xff0c;或者写出优秀的数学建模论文。 在本文中&#xff0c;我将从什么是数学建模、数学建模的应用领域、数学建模的基本步骤、数学建模的技…

DevOps系列文章之 Git知识大全

这里是结合实际业务场景输出。 使用的 Git版本&#xff1a;git version 2.24.0 命令 git log 查看日志&#xff0c;常规操作&#xff0c;必备 # 输出概要日志,这条命令等同于 # git log --prettyoneline --abbrev-commit git log --oneline# 指定最近几个提交可以带上 - 数…

SpringBoot整合SpringData JPA

SpringBoot整合SpringData JPA 下一节直通车 JPA的一对一、一对多、多对多查询 简介 JPA(Java Persistence API)意即Java持久化API&#xff0c;是Sun官方在JDK5.0后提出的Java持久化规范&#xff08;JSR 338&#xff0c;这些接口所在包为javax.persistence&#xff0c;详细…

【《Spring Boot微服务实战(第2版)》——一本关于如何在Spring Boot中构建微服务的全面指南】

使用Spring Boot框架构建基于Java的微服务架构&#xff0c;将应用程序从小型单体架构蜕变为由多个服务组成的事件驱动架构。这个最新版本围绕服务发现、负载均衡、路由、集中式日志、按环境配置和容器化等知识点&#xff0c;循序渐进地讲述微服务架构、测试驱动的开发和分布式系…

Mac 预览(Preview)丢失PDF标注恢复

感谢https://blog.csdn.net/yaoyao_chen/article/details/127462497的推荐&#xff01; 辛苦用预览在pdf上做的阅读标记&#xff0c;关闭后打开全丢失了&#xff0c;推荐尝试下网站导入文件进行恢复&#xff1a; 直接使用该网页应用PDF Annotation Recovery 或者访问该项目&a…

下载|GitLab 2023 年 DevSecOps 全球调研报告:安全左移深入人心、AI/ML 蔚然成风

目录 谁应该对应用程序安全负主要责任&#xff1f; 安全实践的最大挑战 AI 驱动研发&#xff0c;提升研发效率 各个角色使用的工具数量是多少&#xff1f; 一体化 DevSecOps 平台有哪些优势&#xff1f; 56%、74%、71%、65%、57% 这些数字和 DevSecOps 结合在一起&#xf…

MySQL一些知识

六、MySQL命令参数 七、远程登录 use mysql 八、SQL语句和常见的SQL操作 九、数据库和表的创建及插入 指定字段名称&#xff0c;按照表的字段名称顺序写&#xff1a; 指定字段名称&#xff1a; 字段名称可以不全部指定&#xff1a;