图解设计模式:动动手玩转适配器模式

news2024/12/25 12:30:23

前言

📣 📣 📣 📢📢📢
☀️☀️点开就是缘分认识一下,我是小冷。是一个兴趣驱动自学练习两年半的的Java工程师。
📒 一位十分喜欢将知识分享出来的Java博主⭐️⭐️⭐️,擅长使用Java技术开发web项目和工具
📒 文章内容丰富:覆盖大部分java必学技术栈,前端,计算机基础,容器等方面的文章
📒 如果你也对Java感兴趣,关注小冷吧,一起探索Java技术的生态与进步,一起讨论Java技术的使用与学习
✏️高质量技术专栏专栏链接: 微服务数据结构netty,单点登录,SSMSpringCloudAlibaba
😝公众号😝想全栈的小冷,分享一些技术上的文章,以及解决问题的经验
当前专栏设计模式系列
专栏代码地址: 代码地址

适配器模式 Aadpter

这个模式其实在生活中很好就能找到案例:

比如我们的笔记本电脑 都会有一个电源适配器来基于我们笔记本进行供电。

image-20221215200630916

在程序中,经常会现有的程序无法直接使用,会出现需要做适当的变化之后才可以使用到情况。折中用于填补现有程序和所需程序之间差异的设计模式就是Adapter模式

Adapter模式也被称为Wrapper模式,wrapper有包装器的意思,就像用精美的包装纸把商品包装成礼物那样,替我们把代码封装起来,使其可以用于其他用途

Adapter模式有以下两种:

  • 类适配器模式(使用继承的适配器)
  • 对象适配器模式(使用委托的适配器)

类适配器模式

实现思路

首先,让我们来看一段使用继承的适配器的示例程序。这里的示例程序是一段会将输入的字符
串显示为(Hello)或是&Hello&的简单程序。

目前在Banner类中,有将字符用括号括起来的showWithParen方法,和将字符串用&号括起来的showwithAster方法

假设Print接口中声明了两种方法,即字符串显示(加括号)的printWeak方法,和调字符串显示(加&号)的printstrong方法。

现在要做的事情是使用Banner类编写一个实现了Print接口的类,也就是说要做一个将
内容转换的适配器。

扮演适配器角色的是PrintBanner类。该类继承了Banner类并实现了“需求”——Print
接口。PrintBanner类使用showWithParen方法实现了printWeak,使用showwithAster
方法实现了printstrong。这样,PrintBanner类就具有适配器的功能了。

类的对应图

image-20221215221545495

使用了类适配器的示例程序的类图(继承)

image-20221215221615955

示例代码

像上面举例的笔记本电脑的例子

  • banner类 就像是输出 100伏特电压的插座口
  • print接口 就像是输出12伏特电压的输出口
  • printBanner类就像适配器一样,让我们只需要调用print接口就可以拿到banner类的结果
Banner类

作为基类,有提供输出两种不同内容的方法,

public class Banner {
    private String string;

    public Banner(String string) {
        this.string = string;
    }

    public void showWithParen(){
        System.out.println("("+string+")");
    }
    public void showWithAster(){
        System.out.println("&"+string+"&");
    }
}
Print接口

可以理解为 适配器的一端 提供两种输出方式

public interface Print {
    public abstract void printWeak();
    public abstract void printStrong();
}
printBanner类

作为适配器 让需要使用到类只需要调用 print 就可以拿到 banner的结果

public class printBanner extends Banner implements Print {
    public printBanner(String string) {
        super(string);
    }

    @Override
    public void printWeak() {
     showWithParen();
    }

    @Override
    public void printStrong() {
        showWithAster();
    }
}
测试用例
    public static void main(String[] args) {
        Print printBanner = new printBanner("hello");
        printBanner.printWeak();
        printBanner.printStrong();
    }

image-20221215225429498

总结

在main方法中 我们使用到时print 接口,对于main来说 banner对于我们来说是完全隐藏起来的,就像是笔记本只要能在直流12伏特电压下就可以正常工作,他并不知道这12伏特是由适配器将100伏特电压转换而成的。

main类是不知道printBanner类是如何实现的,这样就可以在不用对main类进行修改的情况下,改变printBanner类

使用委托方式的适配器模式

上一个示例我们用类适配器模式了,下面我们再来看看对象适配器模式,在之前的示例程序中,我们用继承实现适配,在这里我们用 “委托” 来实现

PS: 委托可以理解为 把事情交给别人干

类图

类图也是发生了变化 printbanner实例化了banner来做一些事情

image-20221215225846504

示例

public class printBanner1  implements Print {
    private Banner banner;
    public printBanner1(String string) {
        this.banner = new Banner(string);
    }

    @Override
    public void printWeak() {
        banner.showWithParen();
    }

    @Override
    public void printStrong() {
        banner.showWithAster();
    }
}

只需要修改PrintBanner就可以了,这里没有采用继承而是直接生成了banner的示例去调用banner的方法

在Adapter适配器模式中的角色

  • Target 对象 这个角色定义了所需要的方法 print 依照文章开头的例子来说 就是需要使用到12伏特电源
  • Client 使用者 这个角色负责使用被适配后的内容,main 依照例子就是需要使用12伏特电源的电脑
  • Adaptee 被适配 这个角色是一个持有既定方法的角色 依照例子就是一百伏特的插头,由banner扮演此角色,当被适配的角色和target角色方法相同,也就是家庭电压就是12伏特那么就不需要这个角色
  • Adapter 适配器模式的主人公 pringBanner主要负责兼具两侧的功能作为混合,用Adaptee的角色来满足target的要求,这就是适配器模式的目的

拓展思路

什么时候我们需要用上Adapter模式

如果某个方法就是我们所需要的方法,那么直接在程序中使用不就可以了? 很多时候进场会用到的类

实际上,我们在让现有的类适配新的接口时,常常会有 “只要将这里稍微修改一下就可以了” 的想法,一不留神就会修改现有代码,需要注意的是,如果要对已经测试完毕的现有代码进行修改,就必须要在修改后重新测试

Adapter 模式会对现有的类进行适配,生成新的类,通过该模式很方便创建我们需要的方法区,当出现bug的时候,我们明确的知道bug不在现有的类(Apdaptee 角色)中,所以只需要调查Adapter角色的类即可,这样代码的可维护性也提高了

如果没有线程的代码

让现有类适配新的接口时,使用适配器类貌似是一种很不错的解法,但是实际上我们遇到现有类适配新接口时,尝尝会有“只要修改一下就可以使用到”的想法,就会修改现有代码,需要注意的是如果要对已经测试完毕的代码进行修改就会又要测试

兼容性与升级性

软件的生命周期总是版本的升级,当版本升级的时候经常会出现与旧版本的兼容性问题,如果能够完全抛弃旧版本,那么软件维护起来也会轻松一些,但是在日常开发中往往无法抛弃旧版本,这个时候就可以使用适配器版本来做新旧版本的兼容

​ 假设我们今后指向维护新版本那么只需要维护新版本的Adaptee角色,旧版本扮演target角色

拓展示例

Q: 我们为什么用print来使用printbanner的功能 而不是直接用printbanner呢?

A:我们使用print的原因是只需要使用print里的方法,其实用哪一种都是一样,printbanner里的可能还有其他的方法,

拓展代码

请使用适配器模式编写一个将属性集合保存到文件中的FileProperties类中。

这里,我们假设代码的FileIO接口声明了FileProperties需要实现的方法,输入文件file.txt和输出文件newfile.txt的内容如下

输入文件

yaer= 1999

输出文件

day=21
yaer=2004
month=4

main方法为

    public static void main(String[] args) {
        FileIO f = new FileProperties();
        try {
            f.readFromFile("D:\\JavaEngineer\\DesignPatterns\\DesignPattern\\DesignPattern\\src\\main\\java\\hyc\\Adapter\\expand\\file.txt");
            f.setValue("year","2004");
            f.setValue("month","4");
            f.setValue("day","21");
            f.writeToFile("D:\\JavaEngineer\\DesignPatterns\\DesignPattern\\DesignPattern\\src\\main\\java\\hyc\\Adapter\\expand\\newfile.txt");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

fileio类

public interface FileIO {
    void readFromFile(String filename) throws IOException;
    void writeToFile(String filename) throws IOException;
    void setValue(String key,String value);
    String getValue(String key);

}

fileProperties 作为适配fileio和Properties的类

Properties为java.util下的Proerties工具类

public class FileProperties extends Properties implements FileIO {


    @Override
    public void readFromFile(String filename) throws IOException {
        load(new FileInputStream(filename));
    }

    @Override
    public void writeToFile(String filename) throws IOException {
    store(new FileOutputStream(filename),"written by FileProperties");
    }

    @Override
    public void setValue(String key, String value) {
        setProperty(key,value);
    }

    @Override
    public String getValue(String key) {
        return getProperty(key);
    }
}

file文件有上述内容 newfile为空 此时我们执行代码

image-20221216001446993

运行结果

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

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

相关文章

C++进阶 继承

作者:小萌新 专栏:C进阶 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:简单介绍C中继承的概念 继承的概念及定义 继承的概念 继承是一种面向对象编程的概念,它指的是一个类(称为子类…

Win10关闭安全中心的病毒和威胁实时保护

一、遇到问题 想必大家在下载软件时,经常会遇到这样的问题:当我们下载好一个软件安装包时,当双击进行安装时,电脑却报出“无法成功完成操作,因为文件包含病毒或潜在的垃圾软件”。这是Win10的安全中心误以为此为问题软…

ShardingJDBC读写分离

ShardingJDBC是什么 看一看ChatGPT对他的解释: ShardingJDBC是一个数据库连接池,它为数据库的分片和读/写拆分提供支持。它允许您跨多个物理数据库和服务器分发数据,并根据设置的配置将读写操作路由到适当的数据库。 以下是它的工作原理&…

基于java+springmvc+mybatis+vue+mysql的校园拼车系统

项目介绍 本系统采用java语言开发,后端采用ssm框架,前端采用vue技术,数据库采用mysql进行数据存储。 管理员后台页面: 功能:首页、个人中心、学生管理、司机管理、订单信息管理、接单信息管理、留言信息管理 学生后…

小米(Android)刷NetHunter安装指南,无需ssh执行kali命令

一、安装NetHunter 前提:确保手机已经root,已装上magisk。如果没有root,可用尝试magisk root 后执行此文 1、下载Nethunter:Get Kali | Kali Linux 然后push 到sdcard 里, 2、打开magisk,选择刚刚下好的…

【问答篇】Java 基础篇面试题(一)

每天进步一点~ 01、问&#xff1a;空字符串的作用 package com.neuedu.nineteen;public class Test {public static void main(String[] args) {String s"";for (char i a; i < d; i) {ssi;//输出abcsis;//输出cba}System.out.println(s);} } 答&#xff1a;如…

[附源码]Node.js计算机毕业设计高校迎新管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

(五)springcloud之Nacos注册中心-2

最近因口罩事件&#xff0c;也被“阳"了。自己在宿舍&#xff0c;闲来无事。整理下Nacos的注册中心的知识点。 模块&#xff1a; 1.父工程&#xff08;管理版本&#xff09; 2.公共模块&#xff1a;Common-API 3.测试模块&#xff1a;NacosClientConfigConsumer80 版本&am…

Vue3基础语法(⼀)

文章目录02——Vue3基础语法&#xff08;⼀&#xff09;VSCode代码片段模板语法Mustachev-once指令v-textv-htmlv-prev-bind绑定class对象语法数组语法绑定style动态绑定属性绑定一个对象v-on基本使用参数传递修饰符02——Vue3基础语法&#xff08;⼀&#xff09; 上一节中的问…

股票列表接口数据API

国内股票行情股票列表接口数据API&#xff0c;包含5分钟、日线。 JSON返回示例 { "code": "000000", "message": "success", "result": [ "2017-04-10 14:55:00,15.190,15.230,15.180,15.190,3838901", &qu…

毕业设计-基于大数据的股票预测系统-python

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

数据挖掘|主成分分析|

一、主成分分析 在实际问题中&#xff0c;我们经常会遇到研究多个变量的问题&#xff0c;而且在多数情况下&#xff0c;多个变量之间常常存在一定的相关性。由于变量个数较多再加上变量之间常常存在一定的相关性&#xff0c;势必增加了分析问题的复杂性。如何从多个变量中综合为…

2022年下半年的软考成绩今天可以查询啦!!!

自2022年11月5-6日软考考试完成后&#xff0c;经过一个多月的等待&#xff0c;终于在2022年12月15日软考成绩出来啦&#xff01; 相信很多小伙伴们都怀着激动与愉悦的心情&#xff0c;迫切想查询一下自己的成绩&#xff01; 下面是弘博创新小编整理的软考成绩查询流程。 软考成…

Python+QT美颜工具源码

程序示例精选 PythonQT美颜工具源码 如需安装运行环境或远程调试&#xff0c;见文章底部微信名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonQT美颜》编写代码&#xff0c;功能包括了亮度&#xff0c;磨皮&#xff0c;风格化&#xff0c;铅笔化…

软件测试人员一定要会的微信小程序测试点

微信小程序&#xff1a; 不需要下载安装即可使用的应用&#xff0c; 实现了应用“触手可及”的梦想&#xff0c;用户扫一扫或者搜一下即可打开应用。 体现了“用完即走”的理念&#xff0c;用户不用关心是否安装太多应用的问题。 应用将无处不在&#xff0c;随时可用&#…

Mysql分布式锁(一)通过jvm本地锁解决mysql并发问题及可能的失效情况

强烈建议配合之前的JVM本地锁&#xff08;一&#xff09;简单实现阅读 mysql场景 将之前的场景修改为mysql场景&#xff0c;即在数据库中保存一条数据&#xff0c;多个线程并发处理该数据。 数据库建表如下 pom.xml中新增mybatis-plus和mysql <dependency><groupId…

戴尔r730xd服务器从u盘启动设置方法(戴尔r730取消网络启动方法)

1,开机后出现提示的时候&#xff0c;按F12 2,等一会系统会自动进入BIOS选择菜单:选择system bios 回车 3,这时在选择boot setting 回车: 4,在这里选择 BIOS Boot settings 5,将网卡启动的勾选去掉&#xff0c;即默认使用C盘启动 6,退出Esc&#xff0c;会提示保存&#xff0…

C#语言实例源码系列-电脑系统挂机锁

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册 &#x1f449;关于作者 众所周知&#xff0c;人生是一个漫长的流程&#xff0c;不断克服困难&#xff0c;不断反思前进的过程。在这个过程中…

[附源码]Python计算机毕业设计广西助农平台Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

微服务框架 SpringCloud微服务架构 多级缓存 46 JVM 进程缓存 46.2 导入商品案例【导入Demo工程】

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 多级缓存 文章目录微服务框架多级缓存46 JVM 进程缓存46.2 导入商品案例【导入Demo工程】46.2.1 导入商品管理案例demo工程46 JVM 进程缓存 …