14.适配器模式(Adapter Pattern)

news2025/2/7 5:42:50

定义

适配器模式(Adapter Pattern) 是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一种接口。适配器模式通常用于将已有的类或遗留系统中的接口与新系统或目标接口进行兼容,从而能够在系统中无缝地使用不兼容的类。

特性

  • 接口转换:适配器模式通过转换接口,使得不兼容的接口可以一起工作。
  • 包装现有对象:适配器模式不修改现有对象的代码,而是通过创建适配器类来“包装”现有对象,使其符合目标接口的要求。

适用场景

适配器模式适用于以下场景:

  • 接口不兼容:当你需要使用一个已有的类或系统,但它的接口不符合你的需求时,可以通过适配器模式来转换接口。
  • 遗留系统:如果有一个遗留系统,它的接口无法直接与新的系统兼容,适配器可以帮助使遗留系统与新系统一起工作。
  • 第三方库:如果集成了第三方库,并且库的接口与系统不兼容,可以通过适配器模式将库的接口适配成需要的接口。

类设计

适配器模式通常包括以下几个角色:

1.Target(目标接口):定义客户端所需要的接口,通常是期望的接口。
2.Adaptee(遗留接口):需要被适配的现有接口,通常是与目标接口不兼容的接口。
3.Adapter(适配器):将 Adaptee 接口转换成 Target 接口的类,可以通过继承或组合实现。
4.Client(客户端):使用 Target 接口的对象,客户端通过 Target 接口与适配器进行交互。

代码实现解析

我们通过一个简单的例子来演示适配器模式。在这个例子中,我们有一个 旧的接口 IAdaptee 和一个 新的接口 ITarget,并且需要使用一个适配器来使客户端可以通过新的接口使用旧的接口。

优点

  • 促进了类之间的协同工作,即使它们没有直接的关联。
  • 提高了类的复用性。
  • 增加了类的透明度。
  • 提供了良好的灵活性。

缺点

  • 过度使用适配器可能导致系统结构混乱,难以理解和维护。

1. 定义目标接口(新接口)

class ITarget {
public:
    virtual void process() = 0; // 新接口方法
};

ITarget 是客户端期望的接口,process() 方法是客户端需要调用的方法。

2. 定义遗留接口(老接口)

class IAdaptee {
public:
    virtual void foo(int data) = 0;  // 老接口方法
    virtual int bar() = 0;            // 老接口方法
};
IAdaptee 是遗留的接口,里面有两个方法:foo()bar(),这些方法是旧系统或类提供的接口。

3. 旧类实现遗留接口

class OldClass : public IAdaptee {
public:
    void foo(int data) override {
        // 实际业务逻辑
        cout << "OldClass::foo(" << data << ")" << endl;
    }

    int bar() override {
        // 实际业务逻辑
        cout << "OldClass::bar()" << endl;
        return 42; // 返回示例数据
    }
};
OldClass 是实现了 IAdaptee 接口的类,它的接口与客户端所期望的接口不兼容。

4. 适配器实现(对象适配器)

class Adapter : public ITarget {
protected:
    IAdaptee* pAdaptee;  // 组合旧接口的实例

public:
    Adapter(IAdaptee* pAdaptee) : pAdaptee(pAdaptee) {}

    void process() override {
        // 将新接口的调用转发给旧接口的调用
        int data = pAdaptee->bar();  // 调用旧接口的 bar()
        pAdaptee->foo(data);          // 调用旧接口的 foo()
    }
};

对象适配器:在这个实现中,Adapter 类继承了 ITarget 接口,并持有 IAdaptee 的实例。
它将 process() 方法的调用转发到旧接口的 bar()foo() 方法。

组合方式:适配器类通过组合方式引用旧接口类,而不是继承。

5. 客户端调用

int main() {
    IAdaptee* pAdaptee = new OldClass();  // 创建旧接口对象
    ITarget* pTarget = new Adapter(pAdaptee);  // 创建适配器对象

    // 客户端通过适配器调用新接口
    pTarget->process();  // 调用适配器的 process(),内部会调用旧接口的方法

    delete pAdaptee;
    delete pTarget;

    return 0;
}
客户端通过 Adapter 来访问 OldClass,而不需要直接与 OldClass 交互。
客户端只与 ITarget 接口交互。

6. 类适配器实现
适配器也可以通过 多继承 实现,这称为 类适配器。通过继承旧接口,适配器类可以同时继承目标接口和遗留接口。

class Adapter : public ITarget, protected OldClass { // 多继承
public:
    void process() override {
        int data = bar();  // 直接调用旧接口的方法
        foo(data);          // 直接调用旧接口的方法
    }
};
类适配器:在类适配器中,Adapter 类继承了 OldClass,
它不仅实现了 ITarget 接口,而且还继承了 OldClass,可以直接调用 OldClass 的方法。

完整代码:

//目标接口(新接口)
class ITarget{
public:
    virtual void process()=0;
};

//遗留接口(老接口)
class IAdaptee{
public:
    virtual void foo(int data)=0;
    virtual int bar()=0;
};

//遗留类型
class OldClass: public IAdaptee{
    //....
};

//对象适配器
class Adapter: public ITarget{ //继承
protected:
    IAdaptee* pAdaptee;//组合
    
public:
    
    Adapter(IAdaptee* pAdaptee){
        this->pAdaptee=pAdaptee;
    }
    
    virtual void process(){
        int data=pAdaptee->bar();
        pAdaptee->foo(data);
        
    }
    
    
};


//类适配器
class Adapter: public ITarget,
               protected OldClass{ //多继承
               
}

int main(){
    IAdaptee* pAdaptee=new OldClass();
    
    
    ITarget* pTarget=new Adapter(pAdaptee);
    pTarget->process();
    
}


class stack{
    deqeue container;
    
};

class queue{
    deqeue container;
    
};

总结

Adapter 模式的优点:

  • 解耦:客户端与旧接口解耦,客户端通过目标接口与适配器交互,不直接与遗留系统进行交互。
  • 复用:适配器模式可以使旧系统或类重用,而不需要修改旧代码。
  • 适应性强:代理类可以灵活适应不同的接口需求,尤其在接口不兼容时尤为有用。

Adapter 模式的缺点:

  • 增加类的数量:引入适配器类增加了系统的复杂度和类的数量,可能导致代码维护复杂度增加。
  • 性能开销:适配器可能会引入额外的性能开销,尤其是当有多个适配器时。

适用场景:

  • 接口不兼容的类:当现有类的接口与目标接口不兼容时,使用适配器模式可以将接口转换成目标接口,确保客户端可以正常使用。
  • 遗留系统的集成:将遗留系统与新系统进行集成时,适配器模式可以帮助适配旧系统的接口。
  • 第三方库集成:在使用第三方库时,如果库的接口与系统不兼容,适配器模式可以将库的接口适配成系统需要的接口。

总结

适配器模式通过提供一个代理类来将不兼容的接口转换成客户端需要的接口,确保了客户端与系统之间的解耦。通过适配器,客户端可以在不修改现有系统代码的前提下,使用不兼容的类或接口。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Crewai框架配置回调函数

官方文档里只指提了一句 不过不太难&#xff0c;在crew.py文件里配置一下就行了&#xff0c;下面是一个demo&#xff0c;这个函数会在research_task任务执行完触发&#xff08;配置LLM这里请看我这篇博客&#xff09; from crewai import Crew, Process, Agent, Taskfrom src.…

拧紧“安全阀”,AORO-P300 Ultra防爆平板畅通新型工业化通信“大动脉”

在油气管道泄漏的浓烟中&#xff0c;在矿道坍塌的密闭空间里&#xff0c;在洪水肆虐的救援现场&#xff0c;传统通讯设备频频失效的困境已成为历史。AORO-P300 Ultra防爆平板集5G通讯、红外感知、应急照明等实用功能于一体&#xff0c;以军工级防护与全场景智能应用&#xff0c…

基于docker搭建Kafka集群,使用KRaft方式搭建,摒弃Zookeeper

KAFKA基于docker使用KRaft进行集群搭建 环境&#xff1a;已成功搭建kafka服务 可点击链接跳转至安装kafka-3.8.0版本 并启用SASL认证 教程 使用基于Zookeeper方式搭建集群教程 kafka-3.8.0版本 并启用SASL认证 教程 搭建kafka-ui可视化工具 192.168.2.91 192.168.2.92 192…

CAD导入与解析,助力工业数据可视化高效呈现

背景 在企业的日常设计与管理中&#xff0c;CAD图纸早已成为不可或缺的重要资产&#xff0c;多年来知识积累的载体&#xff0c;凝聚了大量的心血与智慧。然而&#xff0c;CAD图纸往往只作为静态文件保存&#xff0c;应用场景较为有限。在数字经济时代&#xff0c;如何让CAD图纸…

基于docker部署kafka-3.8.0版本,并开启SASL认证模式

1、下载安装包 &#xff08;1&#xff09;https://kafka.apache.org/downloads 下载如下图版本 2、解压安装包 执行tar -xvf kafka_2.13-3.8.0.tgz命令对安装包进行解压。 3、增加配置文件 &#xff08;1&#xff09;进入 /kafka_2.13-3.8.0/config 目录 &#xff08;2&a…

从零开始人工智能Matlab案例-KNN的二维数据分类

基于K最近邻&#xff08;K-Nearest Neighbors, KNN&#xff09;算法的二分类案例&#xff0c;包含完整MATLAB代码、算法原理和核心思想说明。此案例使用合成数据集&#xff0c;无需复杂数据预处理&#xff0c;适合快速理解。 案例&#xff1a;基于KNN的二维数据分类 目标&…

Spring AOP 扫盲

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

DeepSeek 提示词之角色扮演的使用技巧

老六哥的小提示&#xff1a;我们可能不会被AI轻易淘汰&#xff0c;但是会被“会使用AI的人”淘汰。 在DeepSeek的官方提示库中&#xff0c;有“角色扮演&#xff08;自定义人设&#xff09;”的提示词案例。截图如下&#xff1a; 在“角色扮演”的提示词案例中&#xff0c;其实…

python3中错误与异常初识

一. 简介 在 编写 Python时&#xff0c;经常会遇到一些报错信息。接下来开始学习 Python3 中错误和异常。 本文首先初步了解一下 Python3中的错误和异常。 二. python3 中错误与异常初识 Python 中有两种错误&#xff1a;语法错误与异常。 1. 语法错误 Python 的语法错误…

【图像处理】- 基本图像操作

基本图像操作详解 基本图像操作是图像处理的基础&#xff0c;涵盖了对图像进行简单但重要的变换。以下是几种常见的基本图像操作及其详细说明&#xff1a; 1. 裁剪 (Cropping) 描述&#xff1a;从原始图像中提取一个矩形区域。 实现方法&#xff1a; 使用图像的坐标系指定…

Attention is All You Need-Transformer模型论文精读+架构分析--简单易懂版

Foreword写在前面的话&#xff1a; 大家好&#xff0c;我是一名刚开始学习Transformer的新手。这篇文章是我在学习Transformer过程中的一些笔记和心得&#xff0c;希望能和同样在学习人工智能深度学习模型的朋友们分享。由于我的知识有限&#xff0c;文章中可能存在错误或不准确…

Qt跨屏窗口的一个Bug及解决方案

如果我们希望一个窗口覆盖用户的整个桌面&#xff0c;此时就要考虑用户有多个屏幕的场景&#xff08;此窗口要横跨多个屏幕&#xff09;&#xff0c;由于每个屏幕的分辨率和缩放比例可能是不同的&#xff0c;Qt底层在为此窗口设置缩放比例&#xff08;DevicePixelRatio&#xf…

Spark--算子执行原理

一、sortByKey SortByKey是一个transformation算子&#xff0c;但是会触发action&#xff0c;因为在sortByKey方法内部&#xff0c;会对每个分区进行采样&#xff0c;构建分区规则&#xff08;RangePartitioner&#xff09;。 内部执行流程 1、创建RangePartitioner part&…

javaEE-6.网络原理-http

目录 什么是http? http的工作原理&#xff1a; 抓包工具 fiddler的使用 HTTP请求数据: 1.首行:​编辑 2.请求头(header) 3.空行&#xff1a; 4.正文&#xff08;body&#xff09; HTTP响应数据 1.首行&#xff1a;​编辑 2.响应头 3.空行&#xff1a; 4.响应正文…

windows版的docker如何使用宿主机的GPU

windows版的docker使用宿主机的GPU的命令 命令如下 docker run -it --nethost --gpus all --name 容器名 -e NVIDIA_DRIVER_CAPABILITIEScompute,utility -e NVIDIA_VISIBLE_DEVICESall 镜像名效果 (transformer) rootdocker-desktop:/# python Python 3.9.0 (default, Nov 15 …

【C++】STL——list的使用

目录 &#x1f495;1.带头双向链表List &#x1f495;2.list用法介绍 &#x1f495;3.list的初始化 &#x1f495;4.size函数与resize函数 &#x1f495;5.empty函数 &#x1f495;6.front函数与back函数 &#x1f495;7.push_front,push_back,pop_front,pop_back函数…

6.PPT:魏女士-高新技术企业政策【19】

目录 NO1234​ NO567 ​ NO1234 创建“PPT.pptx”考生文件夹Word素材文档&#xff1a;选中对应颜色的文字→选中对应的样式单击右键按下匹配对应文字&#xff1a;应用所有对应颜色的文字开始→创建新的幻灯片→从大纲&#xff1a;考生文件夹&#xff1a;Word素材重置 开始→版…

MLA 架构

注&#xff1a;本文为 “MLA 架构” 相关文章合辑。 未整理去重。 DeepSeek 的 MLA 架构 原创 老彭坚持 产品经理修炼之道 2025 年 01 月 28 日 10:15 江西 DeepSeek 的 MLA&#xff08;Multi-head Latent Attention&#xff0c;多头潜在注意力&#xff09;架构 是一种优化…

7.抽象工厂(Abstract Factory)

抽象工厂与工厂方法极其类似&#xff0c;都是绕开new的&#xff0c;但是有些许不同。 动机 在软件系统中&#xff0c;经常面临着“一系列相互依赖的对象”的创建工作&#xff1b;同时&#xff0c;由于需求的变化&#xff0c;往往存在更多系列对象的创建工作。 假设案例 假设…

旋钮屏设备物联网方案,ESP32-C3无线通信应用,助力设备智能化升级

在智能家居的浪潮中&#xff0c;旋钮屏以其独特的交互方式和便捷的操作体验&#xff0c;逐渐成为智能家电控制面板上的新宠儿。从智能冰箱、洗衣机到烤箱、空气炸锅等设备&#xff0c;旋钮屏的应用无处不在。 通过简单的旋转和按压操作&#xff0c;用户可以轻松调节温度、时间…