结构篇-适配器模式

news2025/2/5 9:03:20

文章目录

  • 一、跨越鸿沟靠适配
  • 二、插头与插孔的冲突
    • 1.三相插孔接口
    • 2.两相插孔接口
    • 3.电视机机类TV
    • 4.客户端类
  • 二、通用适配
    • 1. 适配器
    • 2.客户端类
  • 三、专属适配
    • 1.电视机专属适配器
    • 2.客户端类
  • 总结
    • 1. 对象适配器
    • 2. 类适配器
    • 总结


适配器模式(Adapter)通常也被称为转换器,顾名思义,它一定是进行适应与匹配工作的物件。当一个对象或类的接口不能匹配用户所期待的接口时,适配器就充当中间转换的角色,以达到兼容用户接口的目的,同时适配器也实现了客户端与接口的解耦,提高了组件的可复用性。


提示:以下是本篇文章正文内容,下面案例可供参考

一、跨越鸿沟靠适配

对象是多样化的,对象之间通过信息交换,也就是互动、沟通,世界才充满生机,否则就是死水一潭。人类最常用的沟通方式就是语言,两个人对话时,一方通过嘴巴发出声音,另一方则通过耳朵接收这些语言信息,所以嘴巴和耳朵(接口)必须兼容同一种语言(参数)才能达到沟通的目的。试想,我们跟不懂中文的人讲中文一定是徒劳的,因为对方根本无法理解我们在讲什么,更不要说人类和动物对话了,接口不兼容的结果就是对牛弹琴。

对象是多样化的,对象之间通过信息交换,也就是互动、沟通,世界才充满生机,否则就是死水一潭。人类最常用的沟通方式就是语言,两个人对话时,一方通过嘴巴发出声音,另一方则通过耳朵接收这些语言信息,所以嘴巴和耳朵(接口)必须兼容同一种语言(参数)才能达到沟通的目的。试想,我们跟不懂中文的人讲中文一定是徒劳的,因为对方根本无法理解我们在讲什么,更不要说人类和动物对话了,接口不兼容的结果就是对牛弹琴,如图10-1所示。

二、插头与插孔的冲突

举一个生活中常见的实例,我们新买了一台电视机,其电源插头是两相的,不巧的是墙上的插孔却是三相的,这时电视机便无法通电使用。我们以代码来重现这个场景。

1.三相插孔接口

public interface TriplePin {
    // 参数分别是火线、零线、地线
    public void electrify(int l, int n, int e);
}

说明:

  1. 我们为三相插孔接口TriplePin定义了一个三插通电标准electrify(),其中3个参数l、n、e分别对应火线(live)、零线(null)和地线(earth)。

2.两相插孔接口

public interface DualPin {
    // 这里没有地线
    public void electrify(int l, int n);
}

说明:

  1. 与三相插孔接口所不同的是,两相插孔接口DualPin定义的是2个参数的通电标准,可以看到electrify()的参数中缺少了地线e。

3.电视机机类TV

客户端类代码干净、利落,我们将构造出来的女生类实例作为参数传给化妆品装饰器类的构造方法,这就好像为女生外表包裹了一层化妆品一样,对象结构非常生动、形象。接着,我们调用的是化妆品的展示方法show(),运行结果立竿见影,除女生自己的素颜展示结果之外还加上了额外的化妆效果。

public class TV implements DualPin {
    @Override
    public void electrify(int l, int n) {
        System.out.println("火线通电:" + l + ",零线通电:" + n);
        System.out.println("电视开机");
    }
}

说明:

  1. 电视机类TV实现了两相插孔接口DualPin,所以代码第4行的通电方法electrify()只接通火线与零线,然后开机。

4.客户端类

代码很简单,而目前我们面临的问题是,墙上的接口是三相插孔,而电视机实现的是两相插孔,二者无法匹配,如代码所示,客户端无法将两相插头与三相插孔完成接驳。

public class Client {
    public static void main(String[] args) {
        TriplePin triplePinDevice = new TV(); //接口不兼容,此处保持类型不匹配
    }
}

二、通用适配

针对接口不兼容的情况,可能有人会提出比较极端的解决方案,就是把插头掰弯强行适配,若是三相插头接两相插孔的话,就把零线插针拔掉。虽然目的达到了,但经过这么一番暴力修改,插头也无法再兼容其原生接口了,这显然是违背设计模式原则的。为了不破坏现有的电视机插头,我们需要一个适配器来做电源转换,有了它我们便可以顺利地把电视机两相插头转接到墙上的三相插孔中了。

1. 适配器

public class Adapter implements TriplePin {

    private DualPin dualPinDevice;

    //创建适配器时,需要把两插设备接入进来
    public Adapter(DualPin dualPinDevice) {
        this.dualPinDevice = dualPinDevice;
    }

    //适配器实现的是目标接口
    @Override
    public void electrify(int l, int n, int e) {
        //调用被适配设备的两插通电方法,忽略地线参数e
        dualPinDevice.electrify(l, n);
    }
}

说明:

  1. 与电视机类不同的是,适配器类Adapter实现的是三相插孔接口,这意味着它能够兼容墙上的三相插孔了。
  2. 注意代码定义的两相插孔的引用,我们在构造方法中对其进行初始化,也就是说,适配器中嵌入一个两相插孔,任何此规格的设备都是可以接入进来的。
  3. 最后,在实现的三相插孔通电方法中,适配器转去调用了接入的两插设备,并且丢弃了地线参数e,这就完成了三相转两相的调制过程,最终达到适配效果。至此,这个适配器就可以将任意两插设备匹配到三相插孔上了。

2.客户端类

public class Client {
    public static void main(String[] args) {
        DualPin dualPinDevice = new TV();  //构造两插电视机
        TriplePin triplePinDevice = new Adapter(dualPinDevice);  //适配器接驳两端
        triplePinDevice.electrify(1, 0, -1); //此处调用的是三插通电的标准
    }
}
输出结果:
火线通电:1,零线通电:0
电视开机

注意:

  1. 适配器并不关心接入的设备是电视机、洗衣机还是电冰箱,只要是两相插头的设备均可以进行适配,所以说它是一种通用的适配器。

三、专属适配

除了上面所讲的“对象适配器”,我们还可以用“类适配器”实现接口的匹配,这是实现适配器模式的另一种方式。顾名思义,既然是类适配器,那么一定是属于某个类的“专属适配器”,也就是在编码阶段已经将被匹配的设备与目标接口进行对接了。我们继续之前的例子,请参看代码。

1.电视机专属适配器

//I/O流处理类的应用
File file = new File("/压缩包.zip");
ZipInputStream zipInputStream = new ZipInputStream(
     new BufferedInputStream(
         new FileInputStream(file)
    )
);

说明:

  1. 类适配器模式实现起来更简单,如代码所示,电视机专属适配器类中并未包含被适配对象(如电视机)的引用,而是在开始定义类的时候就直接继承自电视机了,此外还一并实现了三相插孔接口。接着在三插通电方法中,我们利用“super”关键字调用父类(电视机类TV)定义的两插通电方法,以实现适配。

2.客户端类

public class Client {
    public static void main(String[] args) {
        TriplePin tvAdapter = new TVAdapter(); //电视机专属三插适配器插入三相插孔
        tvAdapter.electrify(1, 0, -1);
    }
}
输出结果:
火线通电:1,零线通电:0
电视开机

注意:

  1. 如代码所示,我们直接将实例化后的适配器对象接入墙上的三相插孔,接着直接通电使用即可。如输出结果所示,类适配器模式不但使用起来更加简单,而且其效果与对象适配器模式毫无二致。
  2. 这个类适配器是继承自电视机的子类,在类定义的时候就已经与电视机完成了接驳,也就是说,类适配器与电视机的继承关系让它固化为一种专属适配器,这就造成了继承耦合,倘若我们需要适配其他两插设备,它就显得无能为力了。例如要适配两相插头的洗衣机,我们就不得不再写一个“洗衣机专属适配器”,这显然是一种代码冗余,说明适配器兼容性差。
  3. 事物没有绝对的好与坏,对象适配器与类适配器各有各的适用场景。假如我们只需要匹配电视机这一种设备,并且未来也没有任何其他的设备扩展需求,那么类适配器使用起来可能更加简便,所以具体用什么、怎么用还要视具体情况而定,切不要有过分偏执、非黑即白的思想。

总结

众所周知,反复修改代码的代价是巨大的,因为所有依赖关系都要受到牵连,这不但会引入更多没有必要的重构与测试工作,而且其波及范围难以估量,可能会带来不可预知的风险,结果得不偿失。适配器模式让兼容性问题在不必修改任何代码的情况下得以解决,其中适配器类是核心

1. 对象适配器

  1. 对象适配器模式的各角色定义如下。
  • Target(目标接口):客户端要使用的目标接口标准,对应本章例程中的三相插孔接口TriplePin。
  • Adapter(适配器):实现了目标接口,负责适配(转换)被适配者的接口specificRequest()为目标接口request(),对应本章例程中适配器类Adapter。
  • Adaptee(被适配者):被适配者的接口标准,目前不能兼容目标接口的问题接口,可以有多种实现类,对应本章例程中的两相插孔接口DualPin。
  • Client(客户端):目标接口的使用者。

2. 类适配器

在这里插入图片描述

  1. 类适配器模式的各角色定义如下。
  • Target(目标接口):客户端要使用的目标接口标准,对应本章例程中的三相插孔接口TriplePin。
  • Adapter(适配器):实现了目标接口,负责适配(转换)被适配者的接口specificRequest()为目标接口request(),对应本章例程中的电视机专属适配器类TVAdapter。
  • Adaptee(被适配者):被适配者的类实现,目前不能兼容目标接口的问题类,对应本章例程中的电视机类TV。
  • Client(客户端):目标接口的使用者。

总结

  1. 对象适配器模式与类适配器模式基本相同,二者的区别在于前者的Adaptee(被适配者)以接口形式出现并被Adapter(适配器)引用,而后者则以父类的角色出现并被Adapter(适配器)继承,所以前者更加灵活,后者则更为简便。其实不管何种模式,从本质上看适配器至少都应该具备模块两侧的接口特性,如此才能承上启下,促成双方的顺利对接与互动。
  2. 成功利用适配器模式对系统进行扩展后,我们就不必再为解决兼容性问题去暴力修改类接口了,转而通过适配器,以更为优雅、巧妙的方式将两侧“对立”的接口“整合”在一起,顺利化解双方难以调和的矛盾,最终使它们顺利接通。

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

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

相关文章

数字孪生炒得火热,但好像对企业发展还没有任何实质性的突破,是否只是表面功夫?

首先,什么是数字孪生? ​ 数字孪生是充分利用物理模型、传感器更新、运行历史等数据,集成多学科、多物理量、多尺度、多概率的仿真过程,在虚拟空间中完成映射,从而反映相对应的实体装备的全生命周期过程。数字孪生是一…

const成员,流插入,流提取重载,初始化列表!(6千字长文详解!)

c详解之const成员&#xff0c;流插入&#xff0c;流提取重载&#xff0c;初始化列表&#xff01; 文章目录c详解之const成员&#xff0c;流插入&#xff0c;流提取重载&#xff0c;初始化列表&#xff01;<< 流插入 和 >> 流提取的重载解决共有成员函数问题链式访问…

实用!7个强大的Python机器学习库!⛵

&#x1f4a1; 作者&#xff1a;韩信子ShowMeAI &#x1f4d8; 机器学习实战系列&#xff1a;https://www.showmeai.tech/tutorials/41 &#x1f4d8; 本文地址&#xff1a;https://www.showmeai.tech/article-detail/412 &#x1f4e2; 声明&#xff1a;版权所有&#xff0c;转…

如何借助扬尘视频监测系统开展扬尘污染防控工作?

一、方案背景 目前&#xff0c;跟随国家快速发展的步伐&#xff0c;城市化建设也在飞速发展&#xff0c;各种建设工程遍地开花。如何更好抵管理施工扬尘&#xff0c;杜绝各种违规及不文明现象&#xff0c;一直是施工企业、政府管理部门关注的焦点。 二、系统介绍 环境扬尘视频…

手把手教你一套完善且高效的k8s离线部署方案

作者&#xff1a;郝建伟 背景 面对更多项目现场交付&#xff0c;偶而会遇到客户环境不具备公网条件&#xff0c;完全内网部署&#xff0c;这就需要有一套完善且高效的离线部署方案。 系统资源 编号主机名称IP资源类型CPU内存磁盘01k8s-master110.132.10.91CentOS-74c8g40g0…

SkeyeVSS储备地块可视化管理信息系统 助力土地批后全程监管解决方案

一、方案背景 近年来&#xff0c;储备地块经常遭遇倾倒渣土、隐蔽性私搭乱建等违法行为的侵害&#xff0c;在违法行为发生之后又面临追责难度大、效率低的问题&#xff0c;因此可视化监管系统的建设将有效地解决单纯靠人力巡查、巡查时间长、巡查效率低以及发现侵害行为后追责…

阿里云轻量服务器--Docker--Mqtt(eclipse-mosquitto)安装

1 获取镜像&#xff1a; docker pull eclipse-mosquitto:1.6.14查看获取的镜像&#xff1a; docker images 2 安装&#xff1a; 2.1 新建日志和数据目录&#xff1a; # 配置文件存放 mkdir -p /root/mosquitto/config # 数据文件存放 mkdir -p /root/mosquitto/data # 日志文…

安全智能分析技术 神经网络架构搜索

神经网络架构搜索 定义内涵 神经网络架构搜索是为给定数据集自动找到一个或多个架构的任务&#xff0c;这些架构将为给定 的数据集生成具有良好结果的模型&#xff0c;其本质是在高维空间的最优参数搜索问题。 技术背景 深度学习模型的使用越来越大众化&#xff0c;在很多行…

论多线程之中断篇

线程中断一. 启动线程的方式二. 安全中断三. 线程的补充知识3.1 线程常用方法和线程的状态&#xff1a;3.2 线程的优先级概念&#xff1a;一. 启动线程的方式 新启线程的方式 继承Thread类实现Runnable接口&#xff0c;实际上也是通过Thread类来进行线程的操作的 package cn.…

嵌入式:数据处理指令详解

文章目录数据处理指令的特点数据处理指令的汇编格式数据处理指令&#xff0d;指令表&#xff08;1&#xff09;ADD、ADC、SUB、SBC、RSB和RSC&#xff08;2&#xff09;AND、ORR、EOR和BIC&#xff08;3&#xff09;MOV和MVN&#xff08;4&#xff09;CMP和CMN&#xff08;5&am…

如何下载及安装BIGEMAP GIS Office

如何下载及安装BIGEMAP GIS Office 发布时间&#xff1a;2018-01-17 版权&#xff1a; 本产品支持主流winodws操作系统&#xff08;xp sp3,vista,windows 7,windows 8及windows 10 11&#xff09;&#xff0c; 可通过访问Bigemap官网(BIGEMAP-卫星地图_高清卫星地图制图软件_…

791068-69-4,肾素的FRET底物

FRET substrate for renin. excitation at 340 nm, emission at 490 nm.肾素的FRET底物。激发波长为340 nm&#xff0c;发射波长为490 nm。 编号: 182722中文名称: Renin Substrate 1英文名: Renin Substrate 1CAS号: 791068-69-4单字母: H2N-R-E(Edans)-IHPFHLVIHT-K(Dabcyl)-…

PDF如何加密码保护?分享PDF加密的简单方法

PDF 通常是只读的&#xff0c;但如果收件人有特定的编辑软件&#xff0c;它们仍然可以修改&#xff0c;因此当您发送或共享 PDF 文档时&#xff0c;您可能希望使用密码对其进行保护。这样&#xff0c;未经您的许可&#xff0c;任何人都无法读取文件。 如何使用密码保护 pdf 文档…

什么是SD-WAN,它如何改变传统网络?

近年来&#xff0c;网络的构建、管理和运行方式发生了重大变化。许多 IT 管理员现在正在用更高级的网络概念和策略取代传统的网络组件和传统技术。例如&#xff0c;他们越来越依赖网络容器化、自动化、软件定义网络 &#xff08;SDN&#xff09; 和云计算等概念来简化网络。 这…

网络安全和信息化条例

神经网络架构搜索 定义内涵 神经网络架构搜索是为给定数据集自动找到一个或多个架构的任务&#xff0c;这些架构将为给定 的数据集生成具有良好结果的模型&#xff0c;其本质是在高维空间的最优参数搜索问题。 技术背景 深度学习模型的使用越来越大众化&#xff0c;在很多行…

数据处理指令

目录 一、指令 1.1 数据处理指令:数学运算、逻辑运算 1.1.1数据搬移指令 1.1.2机器码 1.1.3立即数 1.1.4数据运算指令基本格式 1.1.5加法指令 1.1.6减法指令、逆向减法指令、乘法指令 1.1.7位运算&#xff08;逻辑运算&#xff09; 1.1.8格式扩展 1.1.9数据运算指令对条…

面试官:Spring Bean的生命周期,你知道吗?

小熊学Java网站&#xff1a;https://javaxiaobear.gitee.io/&#xff0c;每周持续更新干货&#xff0c;建议收藏&#xff01; bean 的生命周期从调用 beanFactory 的 getBean 开始&#xff0c;到这个 bean 被销毁&#xff0c;可以总结为以下七个阶段&#xff1a; 处理名称&…

Aosp系统编译定制系统签名

商业化产品,如果使用默认的签名,一是不安全,而是显得没啥技术。就连谷歌官方也说了,不建议使用testkey作为最终发布版的key,因此,定制系统签名就派上用场了。 具体使用方法谷歌给了一个大致的说法,我们可以在aosp的自述文件中找到,位置位于build\target\product\secur…

建议收藏:数字后端笔试题,含解析

能力归能力&#xff0c;面试归面试&#xff0c;你永远不会知道面试官抛出来的会是什么样的问题。 经历了无数的笔试面试之后&#xff0c;发现数字IC的笔试面试还是有很对共通之处和规律可循的。 之前芯博士为大家分享了一些数字IC面试题&#xff0c;有不少小伙伴私信我&#…

医药企业数字化转型加剧安全风险,“三个关键举措”筑牢数据安全基石

今天&#xff0c;越来越多的医药企业正在探索和寻求数字化手段&#xff0c;赋能“研、产、供、销”各流程&#xff0c;实现生产效率提升。但在数字化过程中&#xff0c;数据安全相较以往也更加严峻&#xff0c;数据泄露频发&#xff0c;形势堪忧。《2021数据泄露成本报告》中&a…