Java设计模式:适配器模式的三种形式(五)

news2024/11/16 8:44:18

在这里插入图片描述

码到三十五 : 个人主页

心中有诗画,指尖舞代码,目光览世界,步履越千山,人间尽值得 !


适配器模式用于将一个类的接口转换为客户端所期望的另一个接口,以实现不兼容接口之间的协作。它像电器插头转换器一样,解决接口不匹配的问题。它有三种形式:类适配器通过继承与实现完成适配,对象适配器通过组合与实现进行适配,而接口适配器则为接口提供默认实现以简化适配。无论哪种方式,目标都是使不兼容的接口能够协同工作,提高代码灵活性和可复用性,降低系统间耦合度。适配器模式广泛应用于旧代码改造、系统升级及跨平台开发等场景。

[参见]:

Java设计模式:核心概述(一)

Java设计模式:单例模式之六种实现方式详解(二)

Java设计模式:工厂模式之简单工厂、工厂方法、抽象工厂(三)

Java设计模式:建造者模式之经典与流式的三种实现(四)

目录

    • 一、什么是适配器模式
      • 角色概念
      • 使用场景
    • 二、适配器模式的三种形式
      • 1. 类适配器模式(Class Adapter Pattern)
        • 代码
        • 使用场景
        • 优点
        • 缺点
      • 2. 对象适配器模式(Object Adapter Pattern)
        • 代码
        • 使用场景
        • 优点
        • 缺点
      • 3. 接口适配器模式(Interface Adapter Pattern)
        • 代码
        • 使用场景
        • 优点
        • 缺点
    • 三、注意事项
    • 四、适配器与装饰器模式的不同

一、什么是适配器模式

适配器模式(Adapter Pattern)的核心概念是将一个类的接口转换成客户期望的另一个接口,从而让原本接口不兼容的类能够合作无间。适配器模式通过引入一个适配器类来实现这种转换,适配器类通常持有源类(即被适配的类)的引用,并实现目标接口(即客户期望的接口)。客户端代码通过调用适配器类的方法来间接调用源类的方法,从而实现接口的适配。

角色概念

适配器模式的角色概念:

  1. 目标接口(Target):客户所期待的接口,也就是适配器需要实现的接口。
  2. 源类/源接口(Adaptee):已存在的类或者接口,其方法或者行为与客户所期待的接口不兼容,需要适配器来进行适配。
  3. 适配器(Adapter):适配器是适配器模式的核心,它是一个类,该类将源类/源接口的方法或行为转换为客户所期待的接口的方法或行为。适配器通过持有源类/源接口的引用,并在其实现的目标接口方法中调用源类/源接口的方法来实现适配。

使用场景

  • 当你想使用一个已经存在的类,但其接口不符合你的需求时,你可以使用适配器模式。
  • 当你想要创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作时,你可以使用适配器模式。例如,在Android开发中,Adapter就是一个典型的适配器模式的应用,它使得ListView等UI组件可以与各种数据源进行协作。
  • 当你需要一个统一的输出接口,而输入类型不可预知时,你可以使用适配器模式。这样,你可以通过适配器将各种输入类型转换为统一的输出接口。

在这里插入图片描述


二、适配器模式的三种形式

适配器模式主要分三种:类适配器模式、对象适配器模式、接口适配器模式(默认适配器模式)。

下面将给出代码,并简要说明它们的使用场景以及各自的优缺点。

1. 类适配器模式(Class Adapter Pattern)

代码
// 源类(Adaptee)
public class Adaptee {
    public void specificRequest() {
        System.out.println("源类特有请求");
    }
}

// 目标接口(Target)
public interface Target {
    void request();
}

// 类适配器(继承源类,实现目标接口)
public class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest(); // 调用源类的方法
        System.out.println("类适配器对请求进行了适配");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Target target = new ClassAdapter();
        target.request();
    }
}
使用场景

当你想将一个已经存在的类适配到一个不兼容的接口,并且这个类的方法在适配器中都会被用到时,可以使用类适配器模式。

优点
  • 适配器可以覆盖源类的方法,提供更灵活的行为控制。
  • 代码结构比较简单,只需继承源类和实现目标接口。
缺点
  • 由于Java不支持多重继承,如果源类已经是某个类的子类,则无法使用类适配器模式。
  • 适配器与源类紧密耦合,源类的任何改变都可能影响适配器。

2. 对象适配器模式(Object Adapter Pattern)

代码
// 源类(Adaptee,与类适配器模式中的相同)

// 目标接口(Target,与类适配器模式中的相同)

// 对象适配器(持有源类的引用,实现目标接口)
public class ObjectAdapter implements Target {
    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest(); // 调用源类的方法
        System.out.println("对象适配器对请求进行了适配");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
    }
}
使用场景

当你想将一个已经存在的类适配到一个不兼容的接口,但你不想使用继承或者源类的方法在适配器中不会被全部用到时,可以使用对象适配器模式。

优点
  • 适配器与源类的关系由继承变为关联,更加灵活。
  • 可以适配多个源类到同一个目标接口,只需在适配器中更换源类对象即可。
缺点
  • 需要额外创建适配器类来适配源类和目标接口。
  • 相比类适配器模式,对象适配器模式的性能可能略低,因为涉及到对象的创建和引用。

3. 接口适配器模式(Interface Adapter Pattern)

代码
// 目标接口(有很多方法)
public interface Target {
    void method1();
    void method2();
    // ... 其他方法
}

// 抽象适配器类(实现目标接口,提供所有方法的默认实现)
public abstract class AbstractAdapter implements Target {
    @Override
    public void method1() { /* 默认实现 */ }
    @Override
    public void method2() { /* 默认实现 */ }
    // ... 其他方法的默认实现
}

// 具体适配器类(继承抽象适配器类,重写需要的方法)
public class ConcreteAdapter extends AbstractAdapter {
    @Override
    public void method1() {
        // 实现具体功能
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Target adapter = new ConcreteAdapter();
        adapter.method1(); // 调用具体功能
        // adapter.method2(); 使用默认实现,如果需要的话
    }
}
使用场景

当一个接口有很多方法,但客户端只对其中的一部分方法感兴趣,或者想要提供一个只需要实现部分方法的默认实现时,可以使用接口适配器模式。

优点
  • 客户端可以只覆盖它感兴趣的方法,对于其他方法可以使用默认实现。
  • 减少了实现接口所需的工作量,因为大部分方法已经有了默认实现。
缺点
  • 如果需要为多个不相关的接口提供适配器,则可能需要为每个接口都创建一个抽象适配器和具体适配器,增加了系统的复杂性。
  • 当接口改变时,可能需要更新抽象适配器以提供新的默认实现。
    在这里插入图片描述

三、注意事项

  • 适配器模式不是在软件设计阶段考虑的问题,而是解决正在服役的项目的问题。也就是说,当你发现已有的类无法满足新的需求时,才考虑使用适配器模式。
  • 适配器模式实现了对原有接口的扩展,而不是修改原有接口或原有类的代码。这是设计模式的一个重要原则:开闭原则(对扩展开放,对修改封闭)。
  • 适配器模式的使用会增加系统的复杂性和理解难度,因为需要引入额外的适配器类。因此,在使用适配器模式时,需要权衡其带来的好处和增加的复杂性。
  • 适配器模式并不一定能解决所有的接口不兼容问题。在某些情况下,可能需要采用其他的设计模式或者重构代码来解决接口不兼容的问题。

四、适配器与装饰器模式的不同

与装饰器模式(Decorator Pattern)相比,适配器模式和装饰器模式都涉及到对类和接口的包装和扩展,但它们的侧重点和目的不同。

1. 侧重点不同:适配器模式主要解决的是接口不兼容的问题,它并不关注对象的功能增强,而是专注于将已有的功能通过适配器类以新的接口形式暴露给客户端。而装饰器模式则侧重于对对象的功能进行扩展和增强,它通常在不改变原有对象的基础上,动态地给对象添加一些额外的职责或行为。

2. 目的不同:适配器模式的主要目的是解决接口不兼容的问题,使得原本无法协同工作的类能够一起工作。而装饰器模式的主要目的是在不改变原有类的基础上,动态地扩展类的功能,增加类的职责。

3. 包装形式不同:适配器模式通常是通过继承或关联关系来实现接口的适配,它可能会改变原有接口的结构和形式。而装饰器模式则是通过组合关系来扩展对象的功能,它通常保持原有接口的稳定性和一致性。

4. 使用场景不同:适配器模式通常用于系统升级、代码重构等场景,当原有系统的接口无法满足新系统的需求时,可以使用适配器模式进行接口的适配。而装饰器模式则常用于需要在运行时动态地给对象添加功能或职责的场景,如Java IO流中的BufferedInputStream、BufferedReader等就是典型的装饰器模式的应用。

综上所述,适配器模式和装饰器模式虽然都涉及到对类和接口的包装和扩展,但它们的侧重点、目的、包装形式和使用场景都有所不同。在实际应用中,应根据具体的需求和场景来选择合适的设计模式。

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

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

相关文章

单调栈(例题+解析)

1、应用场景 找出一个数的左面离概述最近的且小于该数的数&#xff08;同理右面也可以&#xff09; 例如&#xff1a; 数组a[i] 3 4 2 7 5 答案&#xff1a; -1 3 -1 2 2 2、如何实现找到规律 暴力写法&#xff1a; for(int i0;i<n;i) {for(int ji-1;j>0;j--){i…

金融数据采集与风险管理:Open-Spider工具的应用与实践

一、项目介绍 在当今快速发展的金融行业中&#xff0c;新的金融产品和服务层出不穷&#xff0c;为银行业务带来了巨大的机遇和挑战。为了帮助银行员工更好地应对这些挑战&#xff0c;我们曾成功实施了一个创新的项目&#xff0c;该项目采用了先进的爬虫技术&#xff0c;通过ope…

苍穹外卖学习-----2024/03/08

1.新增菜品 工具类AliOssUtil .java Data AllArgsConstructor Slf4j public class AliOssUtil {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;/*** 文件上传** param bytes* param objectName* return*/pub…

STM32day3

1.思维导图 1.总结任务的调度算法&#xff0c;把实现代码再写一下 /* Definitions for myTask02 */ osThreadId_t myTask02Handle; uint32_t myTask02Buffer[ 64 ]; osStaticThreadDef_t myTask02ControlBlock; const osThreadAttr_t myTask02_attributes {.name "myTa…

PostgreSQL容器安装

docker中的centos7中安装 选择对应的版本然后在容器中的centos7中执行下面命令 但是启动容器的时候需要注意 开启端口映射开启特权模式启动init进程 docker run -itd --name centos-postgresql -p 5433:5432 --privilegedtrue centos:centos7 /usr/sbin/init 启动然后进入后先…

Mysql的Cardinality值

什么是Cardinality值&#xff1f; Cardinality值是Mysql做索引优化时一个非常关键的值&#xff0c;优化器会根据这个值来判断是否使用这个索引&#xff0c;它表示索引中唯一值的数目估计值&#xff0c;该值应该尽可能接近1&#xff0c;如果非常小&#xff0c;则用户需要考虑是否…

Clickhouse表引擎介绍

作者&#xff1a;俊达 1 引擎分类 ClickHouse表引擎一共分为四个系列&#xff0c;分别是Log、MergeTree、Integration、Special。其中包含了两种特殊的表引擎Replicated、Distributed&#xff0c;功能上与其他表引擎正交&#xff0c;根据场景组合使用。 2 Log系列 Log系列…

运维知识点-Apache HTTP Server

Apache 介绍 介绍 Apache是一个开源的Web服务器软件&#xff0c;全称为Apache HTTP Server&#xff0c;由Apache软件基金会开发和维护。它是目前全球使用最广泛的Web服务器软件之一&#xff0c;占全球所有网络服务器的很大比例。Apache服务器具有跨平台的特性&#xff0c;可以…

ChatGPT Plus 支付出现「您的银行卡被拒绝/your card has been declined」怎么办?

ChatGPT Plus 支付出现「您的银行卡被拒绝/your card has been declined」怎么办&#xff1f; 在订阅 ChatGPT Plus 或者 OpenAI API 时&#xff0c;有时候会出现已下报错 &#xff1a; Your card has been declined. 您的银行卡被拒绝 出现这种错误&#xff0c;有以下几个解…

Linux操作系统的vim常用命令和vim 键盘图

在vi编辑器的命令模式下&#xff0c;命令的组成格式是&#xff1a;nnc。其中&#xff0c;字符c是命令&#xff0c;nn是整数值&#xff0c;它表示该命令将重复执行nn次&#xff0c;如果不给出重复次数的nn值&#xff0c;则命令将只执行一次。例如&#xff0c;在命令模式下按j键表…

FPGA高端项目:FPGA基于GS2971的SDI视频接收+GTX 8b/10b编解码SFP光口传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收转HDMI输出应用本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放Video Mixer多路视频拼接应用本方案的SDI接收OSD动态字符叠加…

防火墙配置实验

配置 配置IPSec FW1 FW3 NAT策略 FW1 FW3 安全策略 FW1 FW3 最后测试

软考高级:系统工程生命周期方法(计划驱动方法、渐进迭代式方法等)概念和例子

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

Windows按文件类型指定默认应用程序方法,.py文件设置默认打开程序实例演示

有两种方法可以设置按文件类型指定默认应用。 一个是系统的设置&#xff0c;但是部分类型里面是没有的&#xff0c;这种就要通过注册表来添加。 如果没有的话&#xff0c;通过 winR 打开运行&#xff0c;然后输入 regedit 打开注册表&#xff0c;在 计算机\HKEY_CLASSES_ROO…

【leetcode热题】重排链表

给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进行节点交换。 示…

<商务世界>《第8课 Leads——MQL——SQL——商机——成交》

1 各种概念 英文缩写概念Traffic流量Leads潜在客户&#xff0c;销售线索&#xff1b;简称潜在线索MQLMarketing-Qualified Leads市场认可线索SQLSales-Qualified Leads销售认可线索OPPOpportunity商机Account成单客户 2 线索到商机 一般企业会把自身线索进行如下的划分&…

ubuntu18.04编译OpenCV-3.4.19+OpenCV_contrib-3.4.19

首先确保安装了cmake工具 安装opencv依赖文件 sudo apt-get install build-essential sudo apt-get install git libgtk-3-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev sudo apt-get install python3-dev python3-numpy libtbb2 libtbb-dev libjpeg-dev li…

瑞_23种设计模式_模板方法模式

文章目录 1 模板方法模式&#xff08;Template Pattern&#xff09; ★ 钩子函数1.1 介绍1.2 概述1.3 模板方法模式的结构1.4 模板方法模式的优缺点1.5 模板方法模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析&#xff08;InputStre…

Javaweb day13 day14 day15

spring boot 快速入门 写法 http协议 请求协议 响应协议 协议解析 Tomcat

功能强大使用简单的截图/贴图工具,PixPin

一、下载链接 PixPin 截图/贴图/长截图/文字识别/标注 | PixPin 截图/贴图/长截图/文字识别/标注 (pixpinapp.com) 二、功能 截图/贴图/长截图/文字识别/标注 三、安装教程 根据提示安装即可&#xff1a; 四、快捷键 1.软件自带快捷键&#xff08;右击PixPin查看 &#xff09…