设计模式之Adapter模式

2023-11-06

       今天这篇文章,我们来讲将设计模式中的“Adapter模式”,中文就是“适配器模式”。先说说一个生活中适配器模式的案例,有助于理解。现在有一个100伏特的交流电源,我现在想给笔记本充电,但是笔记本只能用12伏特的直流电,那我们是不是不能用这个电源进行充电了?直接充肯定不行,但是我们可以有一个充电器,这个充电器的功能是将100伏特的交流电转化成12伏特的直流电给电脑用。请注意,这句话很重要:“电脑并不知道充电器内部做了些什么,他只知道,可以用”。

       现在运用到编码中来其主要特征就是:已经存在稳定功能的类的时候,新的需求需要去用这个类中所有或者部分功能,或者除此类的功能之外还得加新的功能,那Adapter模式就派上用场了。我们先看代码,然后再来说说细节:

       现在我已经存在一个稳定的类Banner,并且已经测试稳定了,这个类不会再改动。这个类中有两个方法,showWithParen打印出一句话用括弧包起来,还有一个showWithAster打印一句话用星号"*"包起来。现在我有一个需求需要用到这两个方法,需要我去设计一个框架结构来完美的实现。

        传统的编程来说很简单,直接new一个Banner对象,调用这里面的方法就行了。如果我需要更多的功能,那就增加一个类,在新的类中增加别的功能就行了。这种方式那就是面向实现编程了,类和类之间出现强耦合问题,一个类需要修改,相关的类都得改。如果代码出现问题,我们去维护的时候,就需要更改很多个类,并且还不好追踪问题所在。这就不好了,所以才会有了我们的设计模式登场嘛!我们理论的话不多说,往下看!

/**
 * 本案例中,该类是一个早就已经功能稳定的类,现
 * 在在新的版本或者需求中要用到这里面的方法
 * Created by PICO-USER on 2017/3/9.
 */

public class Banner {

    private String string;

    public Banner(String string) {

        this.string = string;

    }

    public void showWithParen() {

        System.out.print("( " + string + " )\n");

    }

    public void showWithAster() {

        System.out.print("* " + string + " *\n");
    }
}

现在这个稳定的Banner类已经存在了,现在我需要定义一个接口Print,这个接口中有两个方法showWeak和showStrong,这两个方法只是表明了行为,显示两句话。具体是怎么实现,得看实现它的类,怎么去实现了。

/**
 * Created by PICO-USER on 2017/3/9.
 */

public interface Print {

    public abstract void showWeak();

    public abstract void showStrong();
}
接着我定义一个类PointBanner,继承了Banner,并且实现了Print接口,很简单,调用了父类的构造方法,和showWithParen方法和showWithAster方法。

/**
 * Created by PICO-USER on 2017/3/9.
 */

public class PrintBanner extends Banner implements Print {

    public PrintBanner(String string) {
        super(string);
    }

    @Override
    public void showWeak() {

        showWithParen();

    }

    @Override
    public void showStrong() {

        showWithAster();
    }
}
现在来看AdapterRun类的调用代码,和实现功能。

public class AdapterRun {

    public static void main(String[] args0) {

        Print print = new PrintBanner("Hello World !");
        print.showWeak();
        print.showStrong();

    }
}
最后的输出结果很简单:

( Hello World ! )
* Hello World ! *

在上面做了这么多事儿,最后就输出了两句话,有网友估计会说,无缘无故的你增加一个Print接口,你这不是更麻烦了吗?其实不然,代码上是多了一些,但是这就将面向实现编程转换成了面向接口编程。面向接口编程,代码量肯定会增加,但是代码的可读性,维护性,灵活性,可拓展性毫无疑问是大大增强的。具体的我们继续往下看。

       细心的网友应该能发现,在AdapterRun类中,我们使用了Print类型来保存了PrintBanner类型的实例。为什么这样做呢?一般的写法是这样的PrintBanner print = new PrintBanner("Hello World !"),我们暂且成这种方式为方式2,示例代码中的方式我们称为方式1。方式1中是完全是使用Print接口调用showWeak方法和showStrong方法,因为是用print去调用的方法,那么你是不能调用showWithParena方法和showWithAster方法的。因为Print跟Banner是两个完全不相干的东西。如果不是按照方式1而是按照方式2,那就是用PrintBanner类去调用方法,这性质就完全变了,因为PrintBanner继承了Banner类,所以这种方式是可以直接调用showWithParen方法和showWithAster方法的。最重要的问题是:我们按着Ctrl点击该方法,方式1跳转到的是Print接口,方式2是跳转的PrintBanner类。问题这就出来了,方式1的使用和接口Print的使用完全将PrintBanner类和Banner类中的方法隐藏起来了,没有暴露出来。AdapterRun类完全不知道PrintBanner类和Banner中方法的实现,他也不需要关心,只需要用就行,这就弱化了PrintBanner类和AdapterRun类的耦合性,当需求更改的时候,我们可以在完全不需要更改AdapterRun类的情况下修改PrintBanner类来实现我们的新需求


     上面是实现接口的方式实现Adapter模式,其实我们也可以用委托的方式来实现Adapter模式。委托就是把这个功能让某人代替去执行,直接看代码:AdapterRun类和Banner类不需要动,只需要把Print接口改成类,然后稍微修改PrintBanner类即可。

/**
 * Created by PICO-USER on 2017/3/9.
 */

public abstract class Print {

    public abstract void showWeak();

    public abstract void showStrong();
}

/**
 * Created by PICO-USER on 2017/3/9.
 */

public class PrintBanner extends Print {
    private Banner banner;

    public PrintBanner(String string) {

        this.banner = new Banner(string);
    }

    @Override
    public void showWeak() {

        banner.showWithParen();
    }

    @Override
    public void showStrong() {

        banner.showWithAster();
    }

思想都是一样的,面向接口编程和面向抽象类编程其实都是面向抽象编程,都一样的。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计模式之Adapter模式 的相关文章

  • “java.io.IOException:连接超时”和“SocketTimeoutException:读取超时”之间有什么区别

    如果我设置一个套接字 SoTimeout 并从中读取 当读取时间超过超时限制时 我会收到 SocketTimeoutException 读取超时 这是我的例子中的堆栈 java net SocketTimeoutException Read
  • 获取文件的锁

    我想在对特定文件开始 threo read 时获取文件上的锁定 以便其他应用程序无法读取已锁定的文件并希望在线程终止时释放锁定文件 您可以获得一个FileLock https docs oracle com javase 8 docs ap
  • 带有 Android 支持库 v7 的 Maven Android 插件

    我使用 maven android plugin 构建我的 android 应用程序 它依赖于 android 支持库 v4 和 v7 由于我没有找到如何从developer android com下载整个sdk 因此我无法使用maven
  • 使用 WebDriver 单击新打开的选项卡中的链接

    有人可以在这种情况下帮助我吗 场景是 有一个网页 我仅在新选项卡中打开所有指定的链接 现在我尝试单击新打开的选项卡中的任何一个链接 在下面尝试过 但它仅单击主 第一个选项卡中的一个链接 而不是在新选项卡中 new Actions drive
  • HAProxy SSL终止+客户端证书验证+curl/java客户端

    我希望使用我自己的自签名证书在 HAProxy 上进行 SSL 终止 并使用我创建的客户端证书验证客户端访问 我通过以下方式创建服务器 也是 CA 证书 openssl genrsa out ca key 1024 openssl req
  • 将SQL数据引入jquery availabletag

    我正在尝试制作自动完成文本框 但如何将 SQL 数据包含到 jquery 可用标记并循环它 我无法根据以下代码执行该功能 任何帮助 将不胜感激 谢谢 这是我的预期输出 预期结果演示 http jsfiddle net VvETA 71 jq
  • 文本在指定长度后分割,但不要使用 grails 打断单词

    我有一个长字符串 需要将其解析为长度不超过 50 个字符的字符串数组 对我来说 棘手的部分是确保正则表达式找到 50 个字符之前的最后一个空格 以便在字符串之间进行彻底的分隔 因为我不希望单词被切断 public List
  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • 如何通过注解用try-catch包装方法?

    如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
  • org/codehaus/plexus/archiver/jar/JarArchiver(不支持的major.minor版本49.0)-Maven构建错误

    下午大家 我在尝试构建项目时收到上述错误 我很确定这与使用 Java 1 6 编译的 Maven 最新更新有关 而我们尝试构建的项目是 1 4 项目 在此之前的插件工作没有问题 因此我将以下内容添加到 POM xml 文件中以尝试强制使用现
  • 添加到列表时有没有办法避免循环?

    我想知道这样的代码 List
  • 虽然我的类已加载,但 Class.forName 抛出 ClassNotFoundException

    代码如下 它的作用是加载我放在主目录中的 jar 文件中的所有类 import java io File import java util jar JarFile import java util jar JarEntry import j
  • Java、Spring:使用 Mockito 测试 DAO 的 DataAccessException

    我正在尝试增加测试覆盖率 所以我想知道 您将如何测试 DAO 中抛出的 DataAccessExceptions 例如在一个简单的 findAll 方法中 该方法仅返回数据源中的所有数据 就我而言 我使用 Spring JdbcTempla
  • 用于缓存的 Servlet 过滤器

    我正在创建一个用于缓存的 servlet 过滤器 这个想法是将响应主体缓存到memcached 响应正文由以下方式生成 结果是一个字符串 response getWriter print result 我的问题是 由于响应正文将不加修改地放
  • 寻找局部最小值

    下面的代码正确地找到了数组的局部最大值 但未能找到局部最小值 我已经进行了网络搜索 以找到找到最小值的最佳方法 并且根据这些搜索 我认为我正在使用下面的正确方法 但是 在几天的时间里多次检查每一行之后 下面的代码中有一些我仍然没有看到的错误
  • Karaf / Maven - 无法解决:缺少需求 osgi.wiring.package

    我无法在 Karaf 版本 3 0 1 中启动捆绑包 该包是使用 Maven 构建的并导入gson http mvnrepository com artifact com google code gson gson 2 3 1 我按照要求将
  • 无需登录即可直接从 Alfresco 访问文件/内容

    我的场景是这样的 我有一个使用 ALFRESCO CMS 来显示文件或图像的 Web 应用程序 我正在做的是在 Java servlet 中使用用户名和密码登录 alfresco 并且我可以获得该登录的票证 但我无法使用该票证直接从浏览器访
  • 我可以限制分布式应用程序发出的请求吗?

    我的应用程序发出 Web 服务请求 提供商处理的请求有最大速率 因此我需要限制它们 当应用程序在单个服务器上运行时 我曾经在应用程序级别执行此操作 一个对象跟踪到目前为止已发出的请求数量 并在当前请求超出允许的最大负载时等待 现在 我们正在
  • 源值 1.5 的错误已过时,将在未来版本中删除

    我使用 scala maven plugin 来编译包含 scala 和 java 代码的项目 我已经将源和目标设置为1 7 但不知道为什么maven仍然使用1 5 这是我在 pom xml 中的插件
  • 如何使用通配符模拟泛型方法的行为

    我正在使用 EasyMock 3 2 我想基于 Spring Security 为我的部分安全系统编写一个测试 我想嘲笑Authentication http docs spring io autorepo docs spring secu

随机推荐

  • Python流体动力学共形映射库埃特式流

    流体动力学简述 在物理学和工程学中 流体动力学是流体力学的一个分支学科 它描述了流体 液体和气体的流动 它有几个子学科 包括空气动力学 研究空气和其他运动中的气体 和流体动力学 研究运动中的液体 流体动力学具有广泛的应用 包括计算飞机上的力
  • 携程酒店数据爬取2020.5

    携程酒店数据爬取2020 5 1 开题 目前网上有好多爬取携程网站的教程 大多数通过xpath beautifulsoup 正则来解析网页的源代码 然后我这个菜b贪方便 直接copy源码的xpath paste在xpath helper改改
  • Kaggle手势符号识别项目实战

    项目数据集地址 https www kaggle com datasets ardamavi sign language digits dataset 观察到数据集已经做过预先的整理 十分工整 txt文件中类别标记清晰详细 项目文件如上图所
  • 小程序+单页+需要服务器,小程序单页设计

    小程序单页设计 内容精选 换一换 I O分析以存储块设备为分析对象 分析得出块设备的I O操作次数 I O数据大小 I O队列深度 I O操作时延等性能数据 并关联到造成这些I O性能数据的具体I O操作事件 进程 线程 调用栈 应用层I
  • iOS自动化布局-AutoLayout约束优先级

    约束的优先级 AutoLayout添加的约束中也有优先级 Priority 优先级的数值1 1000 分为两种情况 一种情况是我们经常添加的各种约束 默认值1000 最大值 优先执行 条件允许的话系统会自动满足我们的约束需求 第二种就是固有
  • 学习OpenCV:rotatedRectangleIntersection计算两个旋转矩形的交集面积

    如图所示 计算两个旋转矩形相交重合区域的顶点 最多返回8个顶点 通过contourArea可返回该顶点集合的面积 void DrawPointSet Mat imgInoutput vector
  • 区块链扫盲之私钥、公钥和地址

    公开密钥 public key 简称公钥 私有密钥 private key 简称私钥 是密码学里非对称加密算法的内容 顾名思义 公钥是可以公开的 而私钥则要进行安全保管 私钥是由随机种子生成的 公钥是将私钥通过算法推导出来 由于公钥太长 为
  • python socket编程之tcp协议多客户端连接

    1 socket 介绍 socket 原意插座 插孔 计算机中一般称为套接字 在同一台计算机中的两个程序可以通过文件 管道 队列等方式进行通信 但是在网络中 两台计算机之间的通讯就需要依靠socket进行通信 2 socket之tcp协议
  • 利用Anaconda完成Python环境安装及配置

    1 Anaconda 1 1 配置过程 Anaconda是一个开源的Python和R编程语言的软件包管理器和环境管理器 用于数据科学和机器学习的开发 进入官网https www anaconda com 下载安装包 next gt arge
  • Host is not allowed to connect to this MySQL server

    意思其实就是我们的MySQL不允许远程登录 所以远程登录失败了 解决方法如下 1 在装有MySQL的机器上登录MySQL mysql u root p密码 2 执行use mysql 3 执行update user set host whe
  • matlab神经网络

    Solve an Input Output Fitting problem with a Neural Network Script generated by Neural Fitting app Created 03 Jan 2022 1
  • vue的常用基础知识

    哈喽 今天不加班 回来整理一下以前的旧笔记 给你们分享一波基础知识 1 Vue模板的使用 div msg vue中的data又属性值 1 2 4 7 5 isShow 真好看 真丑 parseInt 10 2345 div 里面可以写任意j
  • 数据库操作入门速查(1)——Access数据库简单访问

    引用 using System Data OleDb 编写代码 string s Provider Microsoft Jet OLEDB 4 0 Data Source D student zws20151389047 EX1 Datab
  • 启动mongoDB服务

    打开计算机服务 查看mongoDB服务是否已经启动 如果没有自动启动 右键手动启动一下 即可 安装过程中 经常出现一个问题 服务无法自动创建启动 去bin目录下启动mongod exe 提示丢失文件 需要下载安装 去微软官网下载安装 Vis
  • LeetCode--39.组合总和、40组合总和II

    LeetCode 39 组合总和 40组合总和II做题笔记 39 组合总和 题目描述 解题思路 代码 java 40 组合总和II 题目描述 解题思路 代码 java 39 组合总和 题目描述 给定一个无重复元素的数组 candidates
  • 关于TP5400锂电池充放电一体模块 电感“尖叫”(升压Boost电路中 电感有可听见的高频振荡的问题探索与尝试改善)

    TP5400锂电池充放电一体模块电感 尖叫 前言 电感高频振荡人耳可听问题 1 怀疑是电感问题 2 芯片升压功能本身振荡频率低 3 芯片坏了 4 选用电感有问题 猜想 验证 结论 前言 最近一个项目中用到了锂电池充放电电路 之后在 立创开源
  • vue-element表单内使用上传文件,并和表单其他内容一起上传

    vue element 上传文件 表单内使用上传文件 并和表单其他内容一起上传
  • C# 如何只连接一次数据库,然后执行3次查询SQL语句,然后分别把查询结果取到缓冲区中保存

    我有1个数据库共有30个字段 字段名为id 字段2 字段3 字段30 我想只连接一次数据库 然后在数据库中依次查询以下三种符合条件的记录 查找到后取出该记录的字段2 字段3 字段30的数值 1 查找 id xxxxxx01 的记录 将字段2
  • MyBatis工作原理

    MyBatis是一款轻量级的ORM框架 其主要作用就是将Java程序中的数据对象映射到关系数据库中 以下是MyBatis的一些主要知识点小结 MyBatis工作原理 MyBatis的工作原理主要是将Java程序中的SQL语句和关联关系映射到
  • 设计模式之Adapter模式

    今天这篇文章 我们来讲将设计模式中的 Adapter模式 中文就是 适配器模式 先说说一个生活中适配器模式的案例 有助于理解 现在有一个100伏特的交流电源 我现在想给笔记本充电 但是笔记本只能用12伏特的直流电 那我们是不是不能用这个电源