设计模式系列:适配器模式

news2024/10/6 12:23:39

简介

适配器模式(Adapter Pattern)又称为变压器模式,它是一种结构型设计模式。适配器模式的目的是将一个类的接口转换成客户端所期望的另一种接口,从而使原本因接口不匹配而不能一起工作的两个类能够一起工作。

适配器模式有两种形式:类适配器(Class Adapter)和对象适配器(Object Adapter)。类适配器通过继承实现适配器功能,让Adapter实现Target接口并且继承Adaptee,这样Adapter就具备Target和Adaptee的特性,可以将两者进行转化。对象适配器通过对象组合实现适配器功能,将一个对象组合到另一个对象中,以适配其接口。

结构

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

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

案例实现

类适配器

实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。

【例】读卡器

现有一台电脑只能读取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)和测试类。

//创建适配器对象(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));
    }
}

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

优缺点

适配器模式的优点包括:

  1. 扩展性:适配器模式可以用于将一个类的接口转换成客户端所期望的另一个接口,从而使得原本因接口不匹配而不能一起工作的两个类能够一起工作,这使得系统更加灵活和可扩展。
  2. 耦合度降低:通过适配器模式将不兼容的类进行适配,可以将原本耦合度较高的两个类解耦,降低系统的复杂性。
  3. 提高复用性:适配器模式可以将一个类的接口转换成客户端所期望的另一个接口,使得该类可以被更多的客户端使用,提高了代码的复用性。

然而,适配器模式也存在一些缺点:

  1. 增加中转层:适配器模式需要在原有系统基础上增加一个新的适配器层,这会增加系统的复杂性和额外的开销。
  2. 可能引入错误:由于适配器只是转换接口,而不修改原有类的实现,因此如果原有类的实现存在错误,适配器无法修正这些错误。
  3. 不易测试:由于适配器依赖于原有系统,因此对适配器的测试需要依赖于原有系统,增加了测试的难度。

应用场景

  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。

源码中的应用

JDK

Java I/O 库
  • 在 Java I/O 库中,有很多适配器模式的应用。比如,InputStreamReaderOutputStreamWriter 类,它们将字节流适配为字符流,允许读写字符数据而不是字节数据。这些类就充当了适配器的角色,使得不同类型的流可以通过统一的接口进行操作。
Swing GUI 组件
  • 在 Swing GUI 编程中,也有一些适配器模式的应用。例如,WindowAdapterMouseAdapterKeyAdapter 等适配器类,它们实现了对应的监听器接口,但是提供了默认的空实现,使得开发者可以选择性地实现感兴趣的事件处理方法,而不必实现所有的方法。
Arrays 类
  • JDK 中的 Arrays 类提供了很多静态方法来操作数组,其中一些方法就是适配器模式的应用。例如,asList() 方法可以将数组适配为 List 接口的实现类,这样就可以通过 List 的方式来操作数组。
java.util.Collections 类
  • Collections 类中也有一些适配器模式的应用。例如,enumeration() 方法可以将 Enumeration 适配为 Iterator,使得旧的枚举类型可以通过 Iterator 的方式进行遍历。
JDBC(Java Database Connectivity)
  • 在 JDBC 中,ResultSet 对象提供了对数据库查询结果的操作。ResultSet 接口中有一系列的 getXXX() 方法用于获取不同类型的数据,这些方法就是适配器模式的应用,将数据库中的数据适配为 Java 中的基本数据类型。

Spring

Spring MVC 中的适配器
  • 在 Spring MVC 中,HandlerAdapter 充当了适配器的角色。它负责将不同类型的处理器(handler)适配为 HandlerInterceptorHandlerExecutionChain,以便在请求处理流程中调用相应的处理器。
AOP(面向切面编程)中的适配器
  • Spring AOP 使用代理模式来实现切面(Aspect)的横切关注点。在这个过程中,适配器模式也发挥了作用。Spring AOP 通过适配器来将切面(Aspect)适配为通知(Advice),以便在目标方法调用前后或发生异常时执行相应的逻辑。
JDBC 中的适配器
  • 在 Spring 的 JDBC 模块中,JdbcAdapter 类提供了一组适配器方法,用于将不同的数据库厂商提供的 JDBC API 适配为 Spring JDBC 模板中的通用方法。这些适配器方法使得开发者可以以统一的方式访问不同数据库的数据。
消息队列中的适配器
  • 在 Spring Integration 框架中,适配器模式也被广泛应用。例如,MessageAdapter 用于将消息适配为 Spring Integration 中的消息类型,从而与 Spring Integration 的通道和端点进行交互。
测试模块中的适配器
  • 在 Spring Test 模块中,提供了一系列的适配器类,用于将不同的测试框架适配为 Spring Test 上下文中可用的测试类。例如,TestContextManager 适配了 JUnit 和 TestNG 测试框架,使得它们能够在 Spring 测试上下文中进行集成测试。

.Net Core

接口适配器
  • 接口适配器是指适配器类实现了一个接口,并将该接口的方法委托给另一个类的实例。在 .NET Core 中,这种模式常见于接口的默认实现。
  • 例如,在 .NET Core 中的 ASP.NET Core 框架中,IActionResult 接口定义了一种返回结果的标准,而 ActionResult 类则是这个接口的适配器,提供了接口方法的默认实现。
public interface IActionResult
{
    Task ExecuteResultAsync(ActionContext context);
}

public class ActionResult : IActionResult
{
    public virtual Task ExecuteResultAsync(ActionContext context)
    {
        // 提供了接口方法的默认实现
        return Task.CompletedTask;
    }
}
类适配器
  • 类适配器是指适配器类继承了另一个类,并实现了一个接口。在 .NET Core 中,类适配器常见于需要同时继承某个基类并实现某个接口的情况。
  • 例如,Entity Framework Core 中的数据库上下文(DbContext)就是一个类适配器,继承自 DbContextBase 并实现了 IDbContext 接口。
public class DbContext : DbContextBase, IDbContext
{
    // 实现接口方法
    public void SaveChanges()
    {
        // ...
    }
}
对象适配器
  • 对象适配器是指适配器类持有另一个类的实例,并实现一个接口。在 .NET Core 中,对象适配器常见于需要通过组合而非继承来实现适配的情况。
  • 例如,在 .NET Core 中的 HttpClient 类可以被视为一个对象适配器,它持有一个 HttpMessageHandler 实例,并实现了 IDisposable 接口。
public class HttpClient : IDisposable
{
    private readonly HttpMessageHandler _handler;

    public HttpClient(HttpMessageHandler handler)
    {
        _handler = handler;
    }

    // 实现接口方法
    public void Dispose()
    {
        _handler.Dispose();
    }
}

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

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

相关文章

免费的浏览器翻译插件——easypubmed

支持谷歌和edge浏览器,应用商店直接检索安装就可。 非常方便,无论是打算文字还是查单词,只要选中按D,就可以一键翻译啦。 最重要是免费,而且添加了小牛翻译引擎哦。 当然了,此插件本身是给医学生准备的。Pu…

深度学习--CNN应用--VGG16网络和ResNet18网络

前言 我们在学习这两个网络时,应先了解CNN网络的相关知识 深度学习--CNN卷积神经网络(附图)-CSDN博客 这篇博客能够帮我们更好的理解VGG16和RetNet18 1.VGG16 1.1 VGG简介 VGG论文网址:VGG论文 大家有兴趣的可以去研读一下…

JAVA面向对象(下 )(一、继承和方法重写)

一、继承 1.1 什么是继承 生活中继承是指: 继承财产>延续财产 继承/遗传 父母的长相,基因 > 延续上一代的基因 继承技能、专业、职位 >延续 继承中华民族的传统文化 > 延续 青出于蓝而胜于蓝 或 长江后浪推前浪,前浪被拍在…

es安装中文分词器

下载地址,尽量选择和自己本地es差不多的版本 https://github.com/infinilabs/analysis-ik/releases 下载好,解压,把里面的文件放到es的plugins/ik目录下 把plugin-descriptor.properties文件里的es版本改成自己对应的 再启动es,能…

十、OOP面向对象程序设计(五)

1、什么是接口以及接口的运用 1)接口定义 Java接口(Interface),是一些列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能。) 2)接口定义的一般形式 修饰符:…

抖音小店怎么选品?这些超级容易爆单的选品方法,很少有人告诉你!

哈喽~我是电商月月 抖音小店的运营过程中,选品是非常重要的,好的商品不用宣传,就有人看 今天我就来给大家分享几个选品技巧,学会后商品一上架就有流量! 利用数据选品 1.“蝉妈妈”的数据排行榜选品 “蝉妈妈”能看…

在Ubuntu中如何查看NASM -f选项支持的输出格式

2024年4月19日,周五下午 用下面这条指令就可以了: nasm -hf

v1.9.2-httpsok快速申请免费SSL证书

v1.9.2-🔥httpsok快速申请免费SSL证书 介绍 httpsok 是一个便捷的 HTTPS 证书自动续签工具,专为 Nginx 、OpenResty 服务器设计。已服务众多中小企业,稳定、安全、可靠。 一行命令,一分钟轻松搞定SSL证书自动续期 更新日志 V1…

超越现实的展览体验,VR全景展厅重新定义艺术与产品展示

随着数字化时代的到来,VR全景展厅成为了企业和创作者展示作品与产品的新兴选择。通过结合先进的虚拟现实技术,VR全景展厅不仅能够提供身临其境的观展体验,而且还拓展了传统展示方式的界限。 一、虚拟现实技术的融合之美 1、高度沉浸的观展体验…

Pytorch-自动微分模块

🥇接下来我们进入到Pytorch的自动微分模块torch.autograd~ 自动微分模块是PyTorch中用于实现张量自动求导的模块。PyTorch通过torch.autograd模块提供了自动微分的功能,这对于深度学习和优化问题至关重要,因为它可以自动计算梯度&#xff0c…

行人属性AI识别/人体结构化属性AI识别算法的原理及应用场景介绍

行人属性AI识别技术是一种基于人工智能技术的图像识别技术,通过对行人的图像或视频进行处理和分析,提取出其中的结构化信息,如人体姿态、关键点位置、行人属性(性别、年龄、服装等)等。 行人结构化数据分析的方法包括…

什么是边缘计算?它为何如此重要?-天拓四方

随着信息技术的快速发展,数据处理和计算的需求日益增大,特别是在实时性要求极高的场景中,传统的云计算模式面临着巨大的挑战。在这样的背景下,边缘计算作为一种新兴的计算模式,正逐渐受到业界的广泛关注。那么&#xf…

【创建型模式】单例模式

一、单例模式概述 单例模式的定义:又叫单件模式,确保一个类只有一个实例,并提供一个全局访问点。(对象创建型) 要点: 1.某个类只能有一个实例;2.必须自行创建这个实例;3.必须自行向整…

【nginx代理和tengine的启动-重启等命令】

在nginx成功启动后[任务管理器有nginx.exe进程],运行vue项目,在浏览器访问http://localhost:10001/,提示:访问拒绝(调试中network某些地址403); 解决方案: localhost改为ip&#xff…

自动化测试Selenium(4)

WebDriver相关api 定位一组元素 webdriver可以很方便地使用findElement方法来定位某个特定的对象, 不过有时候我们需要定位一组对象, 这时候就要使用findElements方法. 定位一组对象一般用于一下场景: 批量操作对象, 比如将页面上的checkbox都勾上. 先获取一组对象, 再在这组…

【代码随想录】【回文子串】day57:● 647. 回文子串 ● 516.最长回文子序列 ● 动态规划总结篇

回文子串 def countSubstrings(self, s):# 动态规划解法# dp[i][j] s[i-j]区间的回文子串的数目 dp[i][j]取决于dp[i1]和dp[j-1]count0dp[[False]*len(s) for _ in range(len(s))]for i in range(len(s)-1,-1,-1):for j in range(i,len(s)):if s[i]s[j] :if j-i<1:count1dp[…

全新升级轻舟知识付费系统引流变现至上利器

知识付费系统&#xff1a;引流变现至上利器 本系统参考各大主流知识付费系统&#xff0c;汇总取其精华&#xff0c;自主研发&#xff0c;正版授权系统。 我们给你搭建搭建一个独立运营的知识付费平台&#xff0c;搭建好之后&#xff0c;你可以自由的运营管理。网站里面的名称…

嵌入式软件考试——网络基础知识

1 主要知识点 OSI/RMTCP/IPIP地址与网络划分DNS与DHCP网络规划与设计网络故障诊断 2 OSI/RM 2.1 OSI七层模型 OSI七层模型 Bit流&#xff1a;物理层(集中器/中继器) 帧&#xff1a;数据链路层(网桥/交换机) 包&#xff1a;网络层(路由器) 段&#xff1a;传输层 报文&#xf…

SpringBoot框架——7.整合MybatisPlus

这篇主要介绍Springboot整合MybatisPlus&#xff0c;另外介绍一个插件JBLSpringbootAppGen,以及一个经常用于测试的基于内存的h2数据库。 Mybatisplus是mybatis的增强工具&#xff0c;和tk-mybatis相似&#xff0c;但功能更强大&#xff0c;可避免重复CRUD语句&#xff0c;先来…

uniapp_微信小程序_预约时间组件的使用

一、官方文档 DatetimePicker 选择器 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 (uviewui.com) 二、完成的效果 之前使用的是Calendar 日历 这个太耗性能了&#xff0c;直接页面卡顿&#xff0c;所以就换成以上选择器了 三、代码 <u-datetime-p…