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

适配器模式

这个更加好理解,就是做适配功能的类,例如,现在手机没有了圆形耳机接口,只有Type-C接口,因此你如果还想要使用圆形耳机的话需要买个圆形接口转Type-C的转换器(适配器),这就是所谓的适配器,将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

适配器模式(Adapter)包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

类适配器模式

适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。使用一个例子来说明类适配器模式,现有一台电脑只能读取SD卡,而要读取TF卡中的内容的话就需要使用到适配器。创建一个读卡器,将TF卡中的内容读取出来。

举个非常好理解的例子,就好比A是欧洲人,B是日本人,欧洲有个芯片公司只允许欧洲人外貌的人进入吃饭并学习芯片技术,此时日本人想要进去是不行的,会被门卫驱赶。这个时候B最好的方式就是找个适配器,也就是找一套人皮面具扮演成欧洲人就能进去,进去之后吃饭还是这个日本人吃,学习芯片技术也是这个日本人,只不过使用人皮面具蒙混过关而已。而下面是使用SDAdapterTF类 通过implements SDCard 来穿上人皮面具,以适配Computer类方法的参数类型(多态牛逼),而这个多态的运用就是这个人皮面具,而真正功能的实现还是要靠TFCardImpl来实现,而使用TFCardImpl又有两种方式,这里讲第一种通过继承的方式——类适配器模式。

类图如下:
在这里插入图片描述

代码

首先定义我们的电脑实体类、SD卡实体类和TF卡实体类,电脑类仅能读取SD卡,即参数只能传入SDCard的子类,如下:

// 定义Computer类
public class Computer {private String type;public String readSDCard(SDCard sdCard){if(sdCard==null){System.out.println("SD 卡损坏!");}return sdCard.readSD();}public void writeSDCard(SDCard sdCard,String msg){sdCard.writeSD(msg);}
}// 定义SDCard接口
public interface SDCard {String readSD();void writeSD(String msg);
}// 定义TFCard接口
public interface TFCard {String readTF();void writeTF(String msg);
}// SDCard的实现类
public class SDCardImpl implements SDCard{@Overridepublic String readSD() {return "SD卡读出内容:Hello World!";}@Overridepublic void writeSD(String msg) {System.out.println("SD卡写入内容:"+msg);}
}// TFCard的实现类
public class TFCardImpl implements TFCard{@Overridepublic String readTF() {return "TF卡读出内容:Hello World!";}@Overridepublic void writeTF(String msg) {System.out.println("TF卡写入内容:"+msg);}
}

接着定义适配器类,我们电脑只能接受SDCard的子类,而真正完成TF卡的读取功能的是得是TFCard的实现类TFCardImpl ,因此这个适配器应该完全具有TFCardImpl的所有功能,因此需要直接继承TFCardImpl即可,那么如何还要让适配器成为SDCard的子类呢?因为前面已经继承了一个类,因此后面我们使用实现方式实现SDCard接口成为SDCard的子类。这里废话一句:这里的SDCard就好比上面举例的欧洲人皮面具,TFCardImpl好比的是那个日本人。


public class SDAdapterTF extends TFCardImpl implements SDCard{// 特别注意:继承了实现类,实现了SDCard的接口@Overridepublic String readSD() {return super.readTF(); // 调用继承的父类TFCardImpl的方法}@Overridepublic void writeSD(String msg) {super.writeTF(msg); // 调用继承的父类TFCardImpl的方法}
}

客户端测试:

public class Main {public static void main(String[] args) {Computer computer = new Computer();// 对于SD卡是可以直接读取的SDCardImpl sdCard = new SDCardImpl();String msg = computer.readSDCard(sdCard);System.out.println(msg);computer.writeSDCard(sdCard,"你好,世界!");//        对于TF卡,不能直接读取,而要借助适配器来调用TF实现类的方法
//        TFCardImpl tfCard = new TFCardImpl();
//        computer.readSDCard(tfCard)SDAdapterTF sdAdapterTF = new SDAdapterTF();msg = computer.readSDCard(sdAdapterTF);System.out.println(msg);computer.writeSDCard(sdAdapterTF,"你好世界!");}
}

输出:

SD卡读出内容:Hello World!
SD卡写入内容:你好,世界!
TF卡读出内容:Hello World!
TF卡写入内容:你好世界!

可以看到,上述适配器SDAdapterTF实际上就是读卡器嘛!只不过我们的电脑只能接受SD卡的插口,SDAdapterTF扮演的就是TF转SD接口的读卡器。因此其实是让SDAdapterTF继承了TFCardImple,因此可以在里面直接调用TFCardImple的方法,而SDAdapterTF由是SDCard的接口实现类,因此也可以传入到Computer的被读取,多态是面向对象的灵魂!!!超级灵活!

缺点: 类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。那么,这时你可能已经想到了,我可以不继承TFCardImple吗?直接传入TFCardImpl不就好了吗,是的,这种模式非常接近我们的日常生活。也就是下面要讲的对象适配器模式。

对象适配器模式

紧接着上面使用的是继承实现,这里我们讲解第二种实现方式,通过构造器方法传递TFCardImpl对象来实现,实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。我们使用对象适配器模式将读卡器的案例进行改写。类图如下:

在这里插入图片描述

代码

这里只是需要修改一下适配器就行,如果不继承TFCardImpl 还想要调用它的方法应该如何做呢?很简单,让TFCardImpl 的对象作为参数传进来就行,如下:

public class SDAdapterTF implements SDCard {private TFCard tfCard;public SDAdapterTF(TFCard tfCard){this.tfCard = tfCard;}@Overridepublic String readSD() {return tfCard.readTF();}@Overridepublic void writeSD(String msg) {tfCard.writeTF(msg);}
}

客户端测试:

public class Main {public static void main(String[] args) {Computer computer = new Computer();// 对于SD卡是可以直接读取的SDCardImpl sdCard = new SDCardImpl();String msg = computer.readSDCard(sdCard);System.out.println(msg);computer.writeSDCard(sdCard,"你好,世界!");// 对于TF卡需要是有适配器类读取TFCard tfCard = new TFCardImpl();SDAdapterTF sdAdapterTF = new SDAdapterTF(tfCard);msg = computer.readSDCard(sdAdapterTF);System.out.println(msg);computer.writeSDCard(sdAdapterTF,"你好世界!");}
}

输出:

SD卡读出内容:Hello World!
SD卡写入内容:你好,世界!
TF卡读出内容:Hello World!
TF卡写入内容:你好世界!

对象适配器模式其实更加贴近我们的直觉,一般我们将TF卡使用读卡器插入到电脑,而这里的SDAdapterTF对象就是 读卡器+TF 卡,只不过类适配器模式将TFCardImpl直接继承了,相当于焊丝了。而我们的对象适配器模式获取到TFCardImpl是通过构造方法获取到的,更加灵活!因此总结来说,类适配器直接继承,而对象适配器通过构造方法获取对象,仅此而已!

注意:还有一个适配器模式是接口适配器模式。当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter ,实现所有方法。而此时我们只需要继承该抽象类即可。

使用场景: 如果两个类做同一件事(例如本题的存储卡,都是完成数据存取功能的,还比如读取不同编码文件的类)即我有的方法你也要有,只不过各自的方法具体做的不一样,方法中的有些细节不同,可以使用适配器屏蔽掉接口类型的不一致性。

参考内容

传智播客设计模式相关笔记(主要)
https://zhuanlan.zhihu.com/p/369272002

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java SE入门及基础(11)

程序调试 1. 什么是程序调试 当程序出现问题时,我们希望程序能够暂停下来,然后通过我们操作使代码逐行执行,观察整个过程中变量的变化是否按照我们设计程序的思维变化,从而找问题并解决问题,这个过程称之为程序调试…

Grind75第9天 | 733.图像渲染、542.01矩阵、1235.规划兼职工作

733.图像渲染 题目链接:https://leetcode.com/problems/flood-fill 解法: 可以用深度优先搜索和广度优先搜索。 深度优先搜索。每次搜索到一个方格时,如果其与初始位置的方格颜色相同,就将该方格的染色,然后继续对…

SSH远程登录协议

一、SSH的介绍 1.1什么是SSH服务器 SSH(Secure Shell)是一种安全通道协议,主要用来实现字符界面的远程登录、远程 复制等功能。SSH 协议对通信双方的数据传输进行了加密处理,其中包括用户登录时输入的用户口令,SSH 为…

DNS解析原理和k8s DNS 实践

1. 问题背景 1.1 域名解析异常 近期开发的一个功能,需要在k8s集群容器环境中调用公司内部api,api提供了内网域名,解析内网域名异常导致请求超时,因此梳理了下DNS的知识点。 可以先看到下面👇这段配置,修…

Android 13.0 SystemUI下拉状态栏定制二 锁屏页面横竖屏时钟都居中功能实现一

1.前言 在13.0的系统rom定制化开发中,在关于systemui的锁屏页面功能定制中,由于在平板横屏锁屏功能中,时钟显示的很大,并且是在左旁边居中显示的, 由于需要和竖屏显示一样,所以就需要用到小时钟显示,然后同样需要居中,所以就来分析下相关的源码,来实现具体的功能 2.S…

线性代数——(期末突击)概率统计习题(概率的性质、全概率公式)

目录 概率的性质 题一 全概率公式 题二 题三 概率的性质 有限可加性: 若有限个事件互不相容,则 单调性: 互补性: 加法公式: 可分性: 题一 在某城市中共发行三种报纸:甲、乙、丙。在这个…

css宽度适应内容

废话不多说,看如下demo,我需要将下面这个盒子的宽度变成内容自适应 方法有很多,如下 父元素设置display:flex 实现子元素宽度适应内容 如下给父元素设置flex能实现宽度自适应内容 <!DOCTYPE html><html lang"en"><head><meta charset"U…

【K12】Python写分类电阻问题的求解思路解析

分压电阻类电路问题python程序写法 一个灯泡的电阻是20Ω&#xff0c;正常工作的电压是8V&#xff0c;正常工作时通过它的电流是______A。现在把这个灯泡接到电压是9V的电源上&#xff0c;要使它正常工作&#xff0c;需要给它______联一个阻值为______的分压电阻。 解决思想 …

基于Jackson封装的JSON、Properties、XML、YAML 相互转换的通用方法

文章目录 一、概述二、思路三、实现四、测试 一、概述 我们在 yaml转换成JSON、MAP、Properties 通过引入 实现了JSON、Properties、XML、YAML文件的相互转换&#xff0c;具体的类、方法如下&#xff1a; 上面的实现&#xff0c;定义了多个类、多个方法&#xff0c;使用太不…

中仕公考:2024年上半年中小学教师资格考试(笔试)报名已开始

2024年上半年中小学教师资格考试(笔试)报名工作于1月12日开始&#xff0c;此次笔试在31个省(自治区、直辖市)举办&#xff0c;各省(自治区、直辖市)的报名公告将陆续上网。 个别地区报名截止时间有所差异&#xff0c;上海1月13日报名截止&#xff0c;浙江、天津、河南1月14日截…

Redis-Cluster 与 Redis 集群的技术大比拼

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Redis-Cluster 与 Redis 集群的技术大比拼 前言概念与原理对比Redis-Cluster&#xff1a;基于哈希槽的分布式解决方案传统 Redis 集群&#xff1a;主从架构下的数据分片方式 搭建与配置的异同Redis-Cl…

面向对象的三大特征之二:继承 --java学习笔记

什么是继承? 关键字extends,用这个关键字&#xff0c;可以让一个类和另一个类建立起父子关系 继承的特点&#xff1a;子类能继承父类的非私有成员&#xff08;成员变量、成员方法&#xff09;继承后对象的创建&#xff1a;子类的对象时由子类、父类共同完成的 代码演示&am…

杨中科 ASP.NET Core 中的依赖注入的使用

ASP.NET CORE中服务注入的地方 1、在ASP.NET Core项目中一般不需要自己创建ServiceCollection、IServiceProvider。在Program.cs的builder.Build()之前向builderServices中注入 2、在Controller中可以通过构造方法注入服 务。 3、演示 新建一个calculator类 注入 新建TestC…

linux环境安装docker

一、Docker是什么? 当我们开发一个应用程序时&#xff0c;通常需要配置和安装各种软件、库和依赖项。而这些环境配置可能会因为不同的操作系统或版本而存在差异&#xff0c;导致应用在不同环境中运行出现问题。 Docker就像是一个集装箱&#xff0c;可以将应用程序及其所有依…

HTTP 3xx状态码:重定向的场景与区别

HTTP 状态码是服务器响应请求时传递给客户端的重要信息。3xx 系列的状态码主要与重定向有关&#xff0c;用于指示请求的资源已被移动到不同的位置&#xff0c;需要采取不同的操作来访问。 一、301 Moved Permanently 定义&#xff1a; 服务器表明请求的资源已永久移动到一个新…

读元宇宙改变一切笔记07_硬件与互操作性(上)

1. 元宇宙的头号入口 1.1. 元宇宙最令人兴奋的地方在于&#xff0c;我们可以借此开发用来访问、渲染和操纵它的新设备 1.1.1. App Newton于1993年发布&#xff0c;是世界上第一款掌上电脑 1.2. 功能超强大又轻巧的AR和沉浸式VR头显 1.2.1.…

让企业的招投标文件、生产工艺、流程配方、研发成果、公司计划、员工信息、客户信息等核心数据更安全。

PC端访问地址1&#xff1a;www.drhchina.com PC端访问地址2&#xff1a; https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfedee 全方位立体式防护  让数据泄密无处遁形 信息防泄漏是一项系统的整体部署工程&#xff0c;加密监控已成为多数企事业单…

RPA财务机器人在厦门市海沧医院财务管理流程优化汇总的应用RPA全球生态 2024-01-05 17:27 发表于河北

目前国内外研究人员对于RPA机器人在财务管理流程优化领域中的应用研究层出不穷&#xff0c;但现有研究成果主要集中在财务业务单一领域&#xff0c;缺乏财务管理整体流程一体化管控的研究。RPA机器人的功能绝非单一的财务业务处理&#xff0c;无论从自身技术发展&#xff0c;或…

anoconda 安装报错

表现形式&#xff1a;Output folder: D:\anoconda\Lib Extract: _nsis.py Extract: _system_path.py Output folder: D:\anoconda........................ 解决办法&#xff1a; 网址&#xff1a;Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Sour…

C语言实现俄罗斯方块游戏程序设计【附源码】

目录 一、前言 二、需求分析 2.1 产品需求概述 2.1.1 功能简介 2.1.2 运行环境 2.2 功能需求 2.2.1 绘制地图 2.2.2 生成随机方块 2.2.3 按键响应 2.2.4 预览方块 2.2.5 分数累加 三、概要设计 3.1 系统体系结构图 3.2 模块描述 四、详细设计 4.1 系统主要函数…