设计模式之【适配器模式】,两个人之间确实需要月老的搭线~

news2024/11/14 20:44:24

文章目录

  • 一、什么是适配器模式
    • 1、适配器模式使用场景
    • 2、代理、桥接、装饰器、适配器 4 种设计模式的区别
    • 3、适配器模式结构
  • 二、类适配器
    • 1、实例
  • 三、对象适配器
    • 1、实例
  • 四、接口适配器
    • 1、实例
  • 五、源码中的应用

一、什么是适配器模式

适配器模式(Adapter Design Pattern)又叫变压器模式,这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。属于结构型设计模式。

也就是说,当前系统存在两种接口A和B,客户只支持访问A接口,但是当前系统没有A接口对象,但是有B接口对象,但客户无法识别B接口,因此需要通过一个适配器C,将B接口内容转换成A接口,从而使客户能够从A接口获取得到B接口内容。

在软件开发中,基本上任何问题都可以通过增加一个中间层进行解决。适配器模式,其实就是一个中间层。综上,适配器模式其实起着转化/委托的作用,将一种接口转化为另一种符合需求的接口。

适配器模式分为类适配器模式、对象适配器模式、接口适配器模式,类适配器模式中类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

1、适配器模式使用场景

(1)封装有缺陷的接口设计
假设我们依赖的外部系统在接口设计方面有缺陷(比如包含大量静态方法),引入之后会影响到我们自身代码的可测试性。为了隔离设计上的缺陷,我们希望对外部系统提供的接口进行二次封装,抽象出更好的接口设计,这个时候就可以使用适配器模式了。

(2)统一多个类的接口设计
某个功能的实现依赖多个外部系统(或者说类)。通过适配器模式,将它们的接口适配为统一的接口定义,然后我们就可以使用多态的特性来复用代码逻辑。

(3)替换依赖的外部系统
当我们把项目中依赖的一个外部系统替换为另一个外部系统的时候,利用适配器模式,可以减少对代码的改动。

(4)兼容老版本接口
在做版本升级的时候,对于一些要废弃的接口,我们不直接将其删除,而是暂时保留,并且标注为 deprecated,并将内部实现逻辑委托为新的接口实现。这样做的好处是,让使用它的项目有个过渡期,而不是强制进行代码修改。这也可以粗略地看作适配器模式的一个应用场景。

(5)适配不同格式的数据
可以用在不同格式的数据之间的适配。比如,把从不同征信系统拉取的不同格式的征信数据,统一为相同的格式,以方便存储和使用。再比如,Java 中的 Arrays.asList() 也可以看作一种数据适配器,将数组类型的数据转化为集合容器类型。

2、代理、桥接、装饰器、适配器 4 种设计模式的区别

代理、桥接、装饰器、适配器,这 4 种模式是比较常用的结构型设计模式。它们的代码结构非常相似。笼统来说,它们都可以称为 Wrapper 模式,也就是通过 Wrapper 类二次封装原始类。

尽管代码结构相似,但这 4 种设计模式的用意完全不同,也就是说要解决的问题、应用场景不同,这也是它们的主要区别。这里我就简单说一下它们之间的区别。

代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。

桥接模式:桥接模式的目的是将接口部分和实现部分分离,从而让它们可以较为容易、也相对独立地加以改变。

装饰器模式:装饰者模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用。

适配器模式:适配器模式是一种事后的补救策略。适配器提供跟原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。

3、适配器模式结构

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

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

假设当前系统中,客户端需要访问的是Target接口,但Target接口没有一个实例符合要求,而Adaptee实例符合需求;但是客户端无法直接使用Adaptee(接口不兼容),因此,我们需要一个适配器(Adapter)来进行中转,让Adaptee能转化为Target接口形式。

二、类适配器

类适配器是通过继承来实现适配器功能的。

类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。

1、实例

现有一台电脑只能读取SD卡,而要读取TF卡中的内容的话就需要使用到适配器模式。创建一个读卡器,将TF卡中的内容读取出来。
在这里插入图片描述

//SD卡的接口
public interface SDCard {
	//读取SD卡方法
	String readSD();
	//写入SD卡功能
	void writeSD(String msg);
}

//SD卡实现类
public class SDCardImpl implements SDCard {
	public String readSD() {
		String msg = "sd card read a msg :hello word SD";
		return msg;
	}
	public void writeSD(String msg) {
		System.out.println("sd card write msg : " + msg);
	}
}
//电脑类
public class Computer {
	public String readSD(SDCard sdCard) {
		if(sdCard == null) {
			throw new NullPointerException("sd card null");
		}
		return sdCard.readSD();
	}
}
//TF卡接口
public interface TFCard {
	//读取TF卡方法
	String readTF();
	//写入TF卡功能
	void writeTF(String msg);
}

//TF卡实现类
public class TFCardImpl implements TFCard {
	public String readTF() {
		String msg ="tf card read msg : hello word tf card";
		return msg;
	}
	public void writeTF(String msg) {
		System.out.println("tf card write a msg : " + msg);
	}
}
//定义适配器类(SD兼容TF)
public class SDAdapterTF extends TFCardImpl implements SDCard {
	public String readSD() {
		System.out.println("adapter read tf card ");
		return readTF();
	}
	public void writeSD(String msg) {
		System.out.println("adapter write tf card");
		writeTF(msg);
	}
}
//测试类
public class Client {
	public static void main(String[] args) {
		Computer computer = new Computer();
		SDCard sdCard = new SDCardImpl();
		System.out.println(computer.readSD(sdCard));
		System.out.println("------------");
		SDAdapterTF adapter = new SDAdapterTF();
		System.out.println(computer.readSD(adapter));
	}
}

通过增加SDAdapterTF 类,实现的SDCard 接口是电脑支持的,继承的TFCardImpl 是需要适配的。

java是单继承机制,所以只能继承一个,实现另一个。

类适配器模式违背了合成复用原则。通常来讲,我们能用组合,就少用继承。

三、对象适配器

对象适配器是使用组合的方式来实现适配器功能。

1、实例

在这里插入图片描述
类适配器模式的代码,我们只需要修改适配器类(SDAdapterTF)和测试类。

//创建适配器对象(SD兼容TF)
public class SDAdapterTF implements SDCard {
	private TFCard tfCard;
	public SDAdapterTF(TFCard tfCard) {
		this.tfCard = tfCard;
	}
	public String readSD() {
		System.out.println("adapter read tf card ");
		return tfCard.readTF();
	}
	public void writeSD(String msg) {
		System.out.println("adapter write tf card");
		tfCard.writeTF(msg);
	}
}
//测试类
public class Client {
	public static void main(String[] args) {
		Computer computer = new Computer();
		SDCard sdCard = new SDCardImpl();
		System.out.println(computer.readSD(sdCard));
		System.out.println("------------");
		TFCard tfCard = new TFCardImpl();
		SDAdapterTF adapter = new SDAdapterTF(tfCard);
		System.out.println(computer.readSD(adapter));
	}
}

根据“合成复用原则”,在系统中尽量使用关联关系(组合)来替代继承关系。

对象适配器模式是适配器模式常用的一种。使用成本更低,更灵活。

四、接口适配器

接口适配器的关注点与类适配器和对象适配器的关注点不太一样,类适配器和对象适配器着重于将系统存在的一个角色(Adaptee)转化成目标接口(Target)所需内容,而接口适配器的使用场景是解决接口方法过多,如果直接实现接口,那么类会多出许多空实现的方法,类显得很臃肿。此时,使用接口适配器就能让我们只实现我们需要的接口方法,目标更清晰。

1、实例

当我们有这样一个接口:

public interface Person {
	public String read();
	public String write();
	public String walking();
	public String run();
}

我们实现类并不想实现全部的方法,此时我们可以定义一个空的实现类:

public class Personimpl implements Person {
	public String read() {};
	public String write() {};
	public String walking() {};
	public String run() {};
}

我们使用时,只需要继承其空实现类Personimpl,重写我们需要的方法即可。

五、源码中的应用

适配器模式在Spring中应用非常广。

同时,Slf4j也应用了适配器模式,将老的日志实现适配到Slf4j中。

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

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

相关文章

第2天学习Docker——Docker安装

一、前言 Docker 是一个用于开发、传送和运行应用程序的开放平台。Docker 使您能够将应用程序与基础设施分开,以便您可以快速交付软件。使用 Docker,您可以像管理应用程序一样管理基础设施。通过利用 Docker 的快速交付、测试和部署代码的方法&#xff0…

vue3学习一 setup

vue3中没有 data 等配置项, 并且它的引入方式也不是像vue2中的 import vue就可以了, 而是用到什么再引入什么, 其中 setup() 函数, 是最大的区别 vue3中的 setup 有点像vue2中的 data , 但又不完全是 setup 会在 生命周期create…

关于C语言

C99是啥 很多书籍开篇会突然提到C99标准,因此这里搜了一下。 C99是C语言的官方标准第二版。1999年12月1日,国际标准化组织和国际电工委员会旗下的C语言标准委员会正式发布了这个标准文件 ; C99是在C89和C90的基础上发展起来的,增加…

独立站平台选哪个好?5个独立站平台优缺点分析

选择适合自己的独立站平台需要综合考虑多个方面的因素,包括平台的优缺点、自己的需求和预算等因素。下面是几个常见的独立站平台的优缺点分析供您参考: 一、Shopify: 优点:简单易用,拥有丰富的主题和应用程序&#xf…

JavaScript实现求1-100之间不能被3整除的数之和,求100以内偶数的和的两个程序代码

以下为实现求1-100之间不能被3整除数之和求100以内偶数的和的两个程序代码和运行截图 目录 前言 一、实现输入两个数比较两个数的大小 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 二、求100以内偶数的和 2.1 运行流程及思想 2.2 代码段 2.3…

泰坦尼克号幸存者预测(案例)----决策树版

1、导入需要的库 import pandas as pd from sklearn.tree import DecisionTreeClassifier import matplotlib.pyplot as plt from sklearn.model_selection import GridSearchCV2、导入数据 在此下载泰坦尼克号训练数据 data pd.read_csv(r"F:\data\train1.csv") …

内网安全:Cobalt Strike 安装.

内网安全:Cobalt Strike 安装. Cobalt Strike是一款渗透测试神器(又称为CS)。拥有多种协议主机上线方式,集成了端口转发,socket代理,office攻击,文件捆绑,钓鱼,提权&…

哈希算法原理与应用:确保数据完整性和安全性的关键技术

哈希算法是一种将任意长度的消息映射为固定长度摘要或哈希值的算法。哈希算法主要被用于验证数据的完整性和安全性。哈希算法的应用广泛,例如在密码学中用于验证数据完整性和数字签名,也用于检索数据和进行散列分布式存储。下面将详细介绍哈希算法的原理…

《Linux 内核设计与实现》12. 内存管理

文章目录 页区获得页获得填充为 0 的页释放页 kmalloc()gfp_mask 标志kfree()vmalloc() slab 层slab 层的设计slab 分配器的接口 在栈上的静态分配单页内核栈 高端内存的映射永久映射临时映射 每个 CPU 的分配新的每个 CPU 接口 页 struct page 结构表示系统中的物理页&#x…

区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测

区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 区间预测 | MATLAB实现QRCNN卷积神经网络分位数回归时间序列区间预测…

超级详细的 FinalShell 安装 及使用教程

一、引言 FinalShell 是一款免费的国产的集 SSH 工具、服务器管理、远程桌面加速的良心软件,同时支持 Windows,macOS,Linux,它不单单是一个 SSH 工具,完整的说法应该叫一体化的的服务器,网络管理软件,在很大程度上可以…

新唐NUC980使用记录(5.10.y内核):在用户应用中使用GPIO

文章目录 目的使用参考与演示使用参考存在的问题问题定位修改设备树使用测试 总结设备树文件内容 目的 GPIO是最基础的外设,使用频率也非常高,这篇文章将简单体验在NUC980 Liunx用户应用中使用GPIO功能。 这篇文章中内容均在下面的开发板上进行测试&am…

【java EE】Redis基础

Redis基础 业务中会遇到的问题: 数据量巨大数据模式的不确定性数据的频繁读数据的频繁更改大量数据的统计分析 集中数据库的特点 Redis简介: Redis(Remote Dictionary Server)是一个使用ANSI C语言编写的开源数据库高性能的 …

解密Web自动化测试:你需要了解的四大难点

B站首推!2023最详细自动化测试合集,小白皆可掌握,让测试变得简单、快捷、可靠https://www.bilibili.com/video/BV1ua4y1V7Db 目录 前言 问题1:测试稳定性 问题2:测试可维护性 问题3:测试性能 问题4&am…

阿里熔断限流框架Sentinel实现流程和动态规则数据源

文章目录 1.简单介绍2.使用示例3.主要实现原理和组成部分4.动态规则数据源 本篇文章主要介绍熔断限流框架Sentinel的使用示例、组成原理和动态规则数据源的实现原理。 1.简单介绍 阿里的熔断限流框架Sentinel基于滑动时间窗口实现熔断限流管控的,支持多样的管控场景…

PHP 基础入门

目录 1、标记 2、注释 3、输出语句 4、关键字 5、常量的定义与使用 6、预定义常量 7、变量的赋值&#xff08;传参赋值与引用赋值&#xff09; 8、可变变量 9、双引号和单引号的区别 10、heredoc结构和nowdoc结构 11、其他符号 1、标记 <?php 和 ?> 是PHP标…

【MySQL】EXPLAIN 语句 各字段 详解

EXPLAIN 语句 概貌 在连接查询的执行计划中&#xff1a; 每个表都会对应一条记录&#xff0c;这些记录的 id 列的值是相同的&#xff1b; 在包含子查询的执行计划中 &#xff1a;每个 select关键字都会对应一个唯一的 id 值。 驱动表&#xff1a;出现在前面的表&#xff1b; …

Apache ECharts 一个基于 JavaScript 的开源可视化图表库

一&#xff1a; ECharts 特性 ECharts&#xff0c;一个使用 JavaScript 实现的开源可视化库&#xff0c;可以流畅的运行在 PC 和移动设备上&#xff0c;兼容当前绝大部分浏览器&#xff08;IE9/10/11&#xff0c;Chrome&#xff0c;Firefox&#xff0c;Safari等&#xff09;&a…

谷歌正在向所有账户推出密码终止技术

谷歌宣布让其个人帐户持有人使用称为“密码”的密码替代登录的一项重大努力。 该功能面向公司的数十亿帐户推出&#xff0c;用户将能够主动寻找并启用它。谷歌表示&#xff0c;它计划在未来几个月推广密码&#xff0c;并开始推动账户持有人将他们传统的用户名和密码登录转换为…

vscode 远程开发:免密登入设置

文章目录 1. vscode 安装2. vscode 插件安装&#xff08;1&#xff09; 中文界面设置&#xff08;2&#xff09; ssh远程插件安装 3. 免密登入 1. vscode 安装 vscode 官网下载地址&#xff1a;https://code.visualstudio.com/ 安装很简单&#xff1a; 可以默认方式&#xff0…