万字解析设计模式之 适配器模式

news2024/9/28 3:26:26

一、 适配器模式

1.1概述

将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作。

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

适配器模式的实现有两种方式: 类适配器:一次最多只能适配一个适配者类,不能同时适配多个适配者;适配者类不能为最终类;目标抽象类只能为接口,不能为类。 对象适配器:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类;在适配器中置换适配者类的某些方法比较麻烦。

 1.2结构

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

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

1.3 类适配器模式

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

【例】读卡器

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

类图如下:

目标(Target)接口

package com.yanyu.Adapter1;


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

//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);
    }
}

适配者(Adaptee)类:

package com.yanyu.Adapter1;

//TF卡接口
public interface TFCard {
    //读取TF卡方法
    String readTF();
    //写入TF卡功能
    void writeTF(String msg);
}
package com.yanyu.Adapter1;

//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);
    }
}

适配器(Adapter)类

package com.yanyu.Adapter1;

//定义适配器类(SD兼容TF)
public class SDAdapterTF extends TFCardImpl implements SDCard {
    //继承了TFCardImpl类,实现了TF卡的读写功能,并且实现了SDCard接口,使其兼容SD卡

    //实现SD卡的读取方法
    public String readSD() {
        System.out.println("adapter read tf card "); //打印提示信息
        return readTF(); //调用TF卡的读取方法
    }

    //实现SD卡的写入方法
    public void writeSD(String msg) {
        System.out.println("adapter write tf card"); //打印提示信息
        writeTF(msg); //调用TF卡的写入方法
    }
}

客户端类

package com.yanyu.Adapter1;

//电脑类
public class Computer {
    public String readSD(SDCard sdCard) {
        if(sdCard == null) {
            throw new NullPointerException("sd card null");
        }
        return sdCard.readSD();
    }
}
package com.yanyu.Adapter1;

//测试类
public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer(); //创建计算机对象
        SDCard sdCard = new SDCardImpl(); //创建SD卡对象
        System.out.println(computer.readSD(sdCard)); //在计算机上读取SD卡的内容并打印
        System.out.println("------------");

        SDAdapterTF adapter = new SDAdapterTF(); //创建SD适配器对象
        System.out.println(computer.readSD(adapter)); //在计算机上使用适配器读取TF卡的内容并打印
    }
}

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

1.4对象适配器模式

实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。

【例】读卡器

我们使用对象适配器模式将读卡器的案例进行改写。类图如下:

代码如下:

类适配器模式的代码,我们只需要修改适配器类(SDAdapterTF)和测试类。

package com.yanyu.Adapter1;

//定义适配器类(SD兼容TF)

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

//测试类
public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer(); //创建计算机对象
        SDCard sdCard = new SDCardImpl(); //创建SD卡对象
        System.out.println(computer.readSD(sdCard)); //在计算机上读取SD卡的内容并打印
        System.out.println("------------");

        TFCard tfCard = new TFCardImpl();
        SDAdapterTF adapter = new SDAdapterTF(tfCard); //创建SD适配器对象
        System.out.println(computer.readSD(adapter)); //在计算机上使用适配器读取TF卡的内容并打印
    }
}

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

1.5 应用场景

适应的场景:

  • 系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码;
  • 创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作。
  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。

1.6JDK源码解析

在JDK中,有很多使用了适配器模式的地方,其中最常见的是集合框架中的迭代器。迭代器是一种提供对集合元素进行访问的机制,它通常被用于循环遍历集合中的元素。在集合框架中,每个集合都提供了一个迭代器,使得可以使用通用的方式对其进行遍历。

另一个使用适配器模式的例子是JDBC(Java DataBase Connectivity)。JDBC是一种用于连接数据库的API,它提供了一系列的接口。其中,Connection、Statement和ResultSet是最常用的接口。JDBC还提供了一种叫做DriverManager的类,它提供了一个用于建立数据库连接的静态方法getConnection()。在JDBC中,不同的数据库供应商会提供不同的驱动程序,这些驱动程序都实现了JDBC的接口。JDBC驱动程序通常被封装在一个适配器中,使得它们可以与JDBC API协同工作。

二、实验

任务描述

现有一个接口 DataOperation 定义了排序方法 sort(int[]) 和查找方法 search(int[],int),已知类 QuickSort 的 quickSort(int[]) 方法实现了快速排序算法,类 BinarySearch 的 binarySearch(int[],int) 方法实现了二分查找算法。

本关任务:现使用适配器模式设计一个系统,在不修改源代码的情况下将类 QuickSort 和类 BinarySearch 的方法适配到 DataOperation 接口中。

,

实现方式

  1. 确保至少有两个类的接口不兼容:一个无法修改 (通常是第三方、 遗留系统或者存在众多已有依赖的类) 的功能性服务类。一个或多个将受益于使用服务类的客户端类。
  2. 声明客户端接口, 描述客户端如何与服务交互。
  3. 创建遵循客户端接口的适配器类。 所有方法暂时都为空。
  4. 在适配器类中添加一个成员变量用于保存对于服务对象的引用。 通常情况下会通过构造函数对该成员变量进行初始化, 但有时在调用其方法时将该变量传递给适配器会更方便。
  5. 依次实现适配器类客户端接口的所有方法。 适配器会将实际工作委派给服务对象, 自身只负责接口或数据格式的转换。
  6. 客户端必须通过客户端接口使用适配器。 这样一来, 你就可以在不影响客户端代码的情况下修改或扩展适配器。

编程要求

根据提示,在右侧编辑器 Begin-End 内补充 "OperationAdapter.java" 的代码,计算并输出结果。其它文件不需要修改。

测试说明

平台会对你编写的代码进行测试:第一行输入数组个数,第二行输入数组元素,第三行输出需要查询的数。查询的结果 1 表示“找到了”,-1 表示“没有找到”

测试输入: 741 2 58 12 66 98 512; 预期输出: 实现快速排序: 2 5 12 41 58 66 98 实现了二分查找算法: 1

测试输入: 858 40 12 66 77 5 48 2310; 预期输出: 实现快速排序: 5 12 23 40 48 58 66 77 实现了二分查找算法: -1

目标接口

package step1;

public interface DataOperation {
    public void sort(int array[]);
    public int search(int array[],int key);
}

DataOperation接口定义了客户端代码所期望的操作,即sort和search方法,而适配器将快速排序和二分查找算法适配到这个接口中,使得客户端可以统一调用这两种算法。

适配者(Adaptee)类

package step1;

public class BinarySearch {
    public int binarySearch(int array[],int key)
    {
        int low = 0;
        int high = array.length -1;
        while(low <= high)
        {
            int mid = (low + high) / 2;
            int midVal = array[mid];

            if(midVal < key)
            {
                low = mid +1;
            }
            else if(midVal > key)
            {
                high = mid -1;
            }
            else
            {
                return 1; //找到元素返回1
            }
        }
        return -1;  //未找到元素返回-1
    }

}
package step1;

public class QuickSort {
    public int[] quickSort(int array[])
    {
        sort(array,0,array.length-1);
        return array;
    }
    public void sort(int array[],int p, int r)
    {
        int q=0;
        if(p<r)
        {
            q=partition(array,p,r);
            sort(array,p,q-1);
            sort(array,q+1,r);
        }
    }
    public int partition(int[] a, int p, int r)
    {
        int x=a[r];
        int j=p-1;
        for(int i=p;i<=r-1;i++)
        {
            if(a[i]<=x)
            {
                j++;
                swap(a,j,i);
            }
        }
        swap(a,j+1,r);
        return j+1;
    }
    public void swap(int[] a, int i, int j)
    {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

适配器(Adapter)类

package step1;

/********** Begin *********/
// OperationAdapter类实现了DataOperation接口,将QuickSort和BinarySearch适配到DataOperation接口中

public class OperationAdapter implements DataOperation{
    private QuickSort qSort; // 适配者1:快速排序算法
    private BinarySearch binarySearch; // 适配者2:二分查找算法

    // 构造方法,接收快速排序和二分查找算法对象
    public OperationAdapter(QuickSort qSort, BinarySearch binarySearch){
        this.qSort = qSort;
        this.binarySearch = binarySearch;
    }

    // 实现DataOperation接口中的sort方法,调用适配者1的快速排序算法
    public void sort(int[] array){
        qSort.quickSort(array);
    }

    // 实现DataOperation接口中的search方法,调用适配者2的二分查找算法
    public int search(int[] array, int key){
        return binarySearch.binarySearch(array, key);
    }
}
/********** End *********/

客户端类

package step1;

import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        // 创建适配者模式的适配器对象,将快速排序和二分查找算法适配到统一的接口
        DataOperation dataOperation = new OperationAdapter(new QuickSort(),new BinarySearch());
        int i = 0;
        Scanner scanner = new Scanner(System.in);
        int count = scanner.nextInt();
        int[] array = new int[count];
        // 读取输入的数组元素
        while (scanner.hasNext()) {
            array[i++] = scanner.nextInt();
            if (i == array.length) {
                break;
            }
        }
        int key = scanner.nextInt();
        // 使用适配者模式调用快速排序算法
        dataOperation.sort(array);
        System.out.println("实现快速排序:");
        // 输出排序后的数组
        for(i = 0; i<array.length; i++){
            System.out.print(array[i]+" ");
        }
        System.out.println("\n"+"实现了二分查找算法:");
        // 使用适配者模式调用二分查找算法
        System.out.println(dataOperation.search(array, key));
    }
}

 

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

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

相关文章

【ArcGIS Pro二次开发】(77):ArcGIS Pro中图层的获取与解析

一、最简单的获取图层方式 通常情况下&#xff0c;如果要获取当前地图中的图层&#xff0c;可以用2种方法获取。 以下图为例&#xff1a; 一种是【map.Layers】属性获取&#xff0c;结果如下&#xff1a; 可以看出&#xff0c;这里只获取到了第一层级的图层&#xff0c;图层组…

创新无界:通义灵码在测试过程中展现的独特魅力

通义灵码基于通义大模型&#xff0c;提供代码智能生成、研发智能问答能力。本文就来介绍下通义灵码在测试过程中的应用。 操作手册&#xff1a; 通义灵码, 阿里云提供的一款基于通义大模型的智能编码辅助工具_云效-阿里云帮助中心 1. 什么是通义灵码 是阿里云出品的一款基于通…

数据结构与算法实验(黑龙江大学)

实验一 顺序存储的线性表&#xff08;2 学时&#xff09; 一、实验目的 1 、掌握线性表的逻辑结构特征。 2、熟练掌握线性表的顺序存储结构的描述方法。 3 、熟练掌握顺序表上各种基本操作的实现。 二、实验内容 1 、设线性表的数据元素都为整数&#xff0c;存放在顺序表…

C++使用Tensorflow2.6训练好的模型进行预测

要在C语言中调用训练好的TensorFlow模型,需要使用TensorFlow C API。 https://tensorflow.google.cn/install/lang_c?hl=zh-cnten TensorFlow 提供了一个 C API,该 API 可用于为其他语言构建绑定。该 API 在 c_api.h 中定义,旨在实现简洁性和一致性,而不是便利性。 下载…

深度学习卫星遥感图像检测与识别 -opencv python 目标检测 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **深度学习卫星遥感图像检测与识别 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐…

UE5的TimeLine的理解

一直以来&#xff0c;我对动画的理解一直是这样的&#xff1a; 所谓动画&#xff0c;就是可导致可视化内容变化的参数和时间的对应关系。 我不能说这个观点现在过时了&#xff0c;只能说自己狭隘了。因为UE的TimeLine的设计理念真让人竖大拇指。 当我第一次看到TimeLine节点的…

SAP 调取http的x-www-form-urlencoded形式的接口

一、了解下x-www-form-urlencoded形式对于SAP来说有啥区别 简单来说&#xff0c; 1.raw格式就是标准的json格式&#xff1a;{“Name”:“John Smith”&#xff0c;“Age”: 23} 2.x-www格式是要转化一下的&#xff1a;NameJohnSmith&Age23 字段与字段相互连接要用 & 符…

直播间弹幕直播游戏开发教程

随着直播技术的不断发展&#xff0c;交互式弹幕直播游戏成为吸引用户参与的新兴方式。这种游戏融合了实时弹幕互动和直播视频&#xff0c;为观众和主播提供了更加丰富的互动体验。在这篇文章中&#xff0c;我们将探讨从概念到实现的步骤&#xff0c;帮助你打造一款引人入胜的交…

MidJourney笔记(2)-面板使用

MidJourney界面介绍 接着上面的疑问。U1、U2、U3、U4、V1、V2、V3、V4分别代表着什么? U1、U2、U3、U4: U按钮是用于放大图片,数字即表示对应的图片,可以立即生成1024X1024像素大小的图片。这样大家在使用的时候,也方便单独下载。 其中数字顺序如下:

从零开始的搭建指南:开发高效的抖音预约服务小程序

预约服务小程序提高了效率&#xff0c;节省了用户时间。下文&#xff0c;小编将与大家一同探讨如何从零开始打造预约服务小程序。 第一步&#xff1a;明确需求和目标 确定你的小程序主要服务领域是什么&#xff1f;是医疗预约、美容美发、餐厅预订还是其他行业&#xff1f;明…

最新版本的橙色前端微信去水印小程序源码

好像最近去水印小程序挺火的&#xff0c;你看这就不来了一个新的去水印小程序。 橙色前端是最近比较流行的&#xff0c;很多小程序也都是这种样式&#xff0c;如果你需要其它颜色的&#xff0c;可以自己修改一下CSS即可&#xff0c;小程序云开发的&#xff0c;无需服务器。 打…

时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测

时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测 目录 时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 x 基本介绍 1.Matlab实现LSTM-Adaboost时间序列预测…

气相色谱质谱仪样品传输装置中电动针阀和微泄漏阀的解决方案

标题 摘要&#xff1a;针对目前国内外各种质谱仪压差法进样装置无法准确控制进气流量&#xff0c;且无相应配套产品的问题&#xff0c;本文提出了相应的解决方案和配套部件。解决方案主要解决了制作更小流量毛细管和毛细管进气端真空压力精密控制问题&#xff0c;微流量毛细管的…

电子学会C/C++编程等级考试2022年09月(一级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:指定顺序输出 依次输入3个整数a、b、c,将他们以c、a、b的顺序输出。 时间限制:1000 内存限制:65536输入 一行3个整数a、b、c,以空格分隔。 0 < a,b,c < 108输出 一行3个整数c、a、b,整数之间以一个空格分隔。样例输入…

基于51单片机音乐盒LCD1602显示( proteus仿真+程序+原理图+设计报告+讲解视频)

基于51单片机音乐盒LCD1602显示( proteus仿真程序原理图设计报告讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0065 音乐盒 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真…

基于变色龙算法优化概率神经网络PNN的分类预测 - 附代码

基于变色龙算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于变色龙算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于变色龙优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…

LangChain 6根据图片生成推广文案HuggingFace中的image-caption模型

根据图片生成推广文案&#xff0c; 用的HuggingFace中的image-caption模型 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数…

【网络安全】-网络安全的分类详解

文章目录 介绍1. 网络层安全&#xff08;Network Layer Security&#xff09;理论实操使用VPN保护隐私 2. 应用层安全&#xff08;Application Layer Security&#xff09;理论实操使用密码管理器 3. 端点安全&#xff08;Endpoint Security&#xff09;理论实操定期更新防病毒…

79基于matlab的大米粒中杂质识别

基于matlab的大米粒中杂质识别&#xff0c;数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 79matlab图像处理杂质识别 (xiaohongshu.com)

hm商城微服务远程调用及拆分

RequiredArgsConstructor是Lombok库中的一个注解 它会自动在类中生成一个构造函数&#xff0c;这个构造函数会接收类中所有被标记为final的字段&#xff0c;并将其作为参数。这个注解可以帮助我们减少样板代码&#xff0c;例如手动编写构造函数。 eg&#xff1a; public fin…