设计模式(六)-----适配器模式(Adapter Pattern)

news2025/1/16 17:08:56

目录

  • 什么是适配器模式
  • 适用场景
  • 适配器模式的三种实现方式
    • 1. 类的适配器模式
    • 2. 对象的适配器模式
    • 3. 接口的适配器模式
  • 总结

什么是适配器模式

适配器模式主要用于将一个类的接口转化成客户端希望的目标类格式,使得原本不兼容的类可以在一起工作,将目标类和适配者类解耦;同时也符合“开闭原则”,可以在不修改原代码的基础上增加新的适配器类;将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性,但是缺点在于更换适配器的实现过程比较复杂。

适用场景

  • 将旧的接口适配成新的接口
    在软件开发中,我们经常会遇到需要使用旧的类或组件,但它们的接口与我们期望的接口不兼容的情况。这时候,我们可以使用适配器模式将旧的接口适配成新的接口,使其能够协同工作。例如,Java中的InputStreamReader类就是一个适配器模式的应用,它将字节流转换成字符流,以便于读取文本文件。

  • 将多个类的接口适配成统一的接口
    在某些情况下,我们可能需要将多个类的接口适配成统一的接口,以便于我们能够使用它们的共同特性。例如,Java中的Enumeration接口定义了一组方法,可以遍历集合中的元素。但是,在Java 1.0中,集合类没有实现这个接口,而是使用了一个名为"elements"的方法。为了使集合类能够遵循Enumeration接口,Java提供了一个适配器类叫做"Iterator",它将"elements"方法适配成Enumeration接口的方法。

  • 在不改变原有代码的情况下,增加新的功能
    适配器模式还可以用于在不改变原有代码的情况下,增加新的功能。例如,如果我们想要给一个已经存在的类增加一些额外的功能,但是又不想修改这个类的代码,那么我们可以使用适配器模式来实现这个目的。具体的做法是,创建一个适配器类,将原有类的对象作为适配器类的成员变量,并在适配器类中添加新的方法。

适配器模式的三种实现方式

1. 类的适配器模式

  • 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
  • 需要适配的类(Adaptee):需要适配的类或适配者类。
  • 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。

完整代码

已存在的,但是拥有不符合我们要求接口的类

public class Adaptee {
    public void specificRequest() {
        System.out.println("被适配类具有 特殊功能...");
    }
}

目标接口,就是我们需要的统一接口

public interface Target {
    void request();
}

具体目标类,只提供普通功能,就是实现统一接口的普通类

public class ConcreteTarget implements Target{
    @Override
    public void request() {
        System.out.println("我是普通类,实现普通功能");
    }
}

适配器类,继承了被适配类,同时实现标准接口

public class Adapter extends Adaptee implements Target{
    @Override
    public void request() {
        super.specificRequest();
    }
}

测试

public class Client {
    public static void main(String[] args) {
        // 使用普通功能类
        Target concreteTarget = new ConcreteTarget();
        concreteTarget.request();

        // 使用特殊功能类,即适配类
        Target adapter = new Adapter();
        adapter.request();

    }
}

结果
在这里插入图片描述

2. 对象的适配器模式

class Adapter implements Target{
	// 直接关联被适配类
	private Adaptee adaptee;
	
	// 可以通过构造函数传入具体需要适配的被适配类对象
	public Adapter (Adaptee adaptee) {
		this.adaptee = adaptee;
	}
	
	public void request() {
		// 这里是使用委托的方式完成特殊功能
		this.adaptee.specificRequest();
	}
}
 
// 测试类
public class Client {
	public static void main(String[] args) {
		// 使用普通功能类
		Target concreteTarget = new ConcreteTarget();
		concreteTarget.request();
		
		// 使用特殊功能类,即适配类,
		// 需要先创建一个被适配类的对象作为参数
		Target adapter = new Adapter(new Adaptee());
		adapter.request();
	}
}

测试结果与上面的一致。从类图中我们也知道需要修改的只不过就是 Adapter 类的内部结构,即 Adapter 自身必须先拥有一个被适配类的对象,再把具体的特殊功能委托给这个对象来实现。使用对象适配器模式,可以使得 Adapter 类(适配类)根据传入的 Adaptee 对象达到适配多个不同被适配类的功能,当然,此时我们可以为多个被适配类提取出一个接口或抽象类。这样看起来的话,似乎对象适配器模式更加灵活一点。

3. 接口的适配器模式

有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行

public interface Sourceable {
    void method1();

    void method2();

    void method3();

    void method4();
}
public abstract class Wrapper implements Sourceable{
    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }

    @Override
    public void method3() {

    }

    @Override
    public void method4() {

    }
}
public class WrapperSub extends Wrapper{
    @Override
    public void method1() {
        System.out.println("是我method1");
    }
}
public class WrapperSub1 extends Wrapper{
    @Override
    public void method2() {
        System.out.println("我是method2");
    }
}
public class Client {
    public static void main(String[] args) {
        WrapperSub wrapperSub = new WrapperSub();
        wrapperSub.method1();

        WrapperSub1 wrapperSub1 = new WrapperSub1();
        wrapperSub1.method2();
    }
}

在这里插入图片描述

总结

适配器模式是一种非常常见的设计模式,它可以帮助我们解决不兼容的类或接口之间的问题,同时也可以帮助我们在不改变原有代码的情况下,增加新的功能。

参考:

https://blog.csdn.net/2302_77835532/article/details/130664014
https://blog.csdn.net/a745233700/article/details/83628122

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

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

相关文章

2023年7月北京/广州/深圳制造业产品经理NPDP认证招生

产品经理国际资格认证NPDP是新产品开发方面的认证,集理论、方法与实践为一体的全方位的知识体系,为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会(PDMA)成立于1979年,是…

Windows 10 实现实时文件夹同步的方法

什么是实时同步? 实时文件夹同步是一种确保在满足一定条件时立即更新一个或多个文件夹的过程。与传统的文件同步方法相比,它能够更及时地检测到源文件夹的变化并将这些变化快速复制到目标文件夹。 实时文件夹同步可以采用单向同步或双向同步的模式…

Flutter 状态管理框架 Provider 和 Get 分析

状态管理一直是 Flutter 开发中一个火热的话题。谈到状态管理框架,社区也有诸如有以Get、Provider为代表的多种方案,它们有各自的优缺点。面对这么多的选择,你可能会想:「我需要使用状态管理么?哪种框架更适合我&#…

数据安全之风险评估(三)

网络数据安全风险评估坚持预防为主、主动发现、积极防范,对数据处理者数据安全保护和数据处理活动进行风险评估,旨在掌握数据安全总体状况,发现数据安全隐患,提出数据安全管理和技术防护措施建议,提升数据安全防攻击、…

ElasticSearch简单介绍以及基本概念阐述

文章目录 一、ES是什么二、ES主要功能1、实时数据搜索和分析:2、分布式架构:3、全文搜索:4、实时数据分析:5、多种数据类型支持:6、实时监控和可视化:7、安全性和访问控制:8、多种集成和扩展&am…

java-error-No converter found for return value of type

java-error-No converter found for return value of type 问题描述 : 日志如下 : 14-Jul-2023 15:27:46.747 严重 [http-nio-8080-exec-5] org.apache.catalina.core.StandardWrapperValve.invoke 在路径为[]的上下文中,Servlet[action]的…

掘金量化—Python SDK文档—3.变量约定

目录 Python SDK文档 3.变量约定 3.1 symbol - 代码标识 3.1.1交易所代码 3.1.2交易标的代码 3.1.3symbol 示例 3.1.4期货主力连续合约 3.2mode - 模式选择 3.2.1实时模式 3.2.2回测模式 3.3context - 上下文对象 3.3.1context.symbols - 订阅代码集合 3.3.2context.now - 当…

【PHP面试题46】php-fpm的工作模式是什么,如何进行配置?

文章目录 一、前言二、PHP-FPM的工作模式三、进程数量配置依据四、php-fpm常见的配置参数4.1 pm.max_children4.2 pm.start_servers4.3 pm.min_spare_servers4.4 pm.max_spare_servers4.5 pm.max_requests4.6 request_terminate_timeout4.7 max_input_time4.8 upload_max_files…

UE4 常用控制台命令

ue4执行控制台命令有两种方式,一是在运行时按~呼出控制台输入命令后回车执行,二是调用蓝图函数ExecuteConsoleCommand函数传入参数执行命令,需要注意shipping包无法执行控制台命令 常用命令: Stat FPS 显示帧率 Stat Slate 显示…

激斗云计算:互联网大厂打响新一轮排位战

大模型如同一辆时代列车,所有科技大厂都想上车。 自去年底ChatGPT一炮而红,国内外数十家科技大厂、创业公司、机构相继下场,一时间掀起大模型的热浪。 《中国人工智能大模型地图研究报告》显示,截至今年5月28日,中国…

http连接处理(中)(四)

2. 结合代码分析请求报文解析 上一节我们对http连接的基础知识、服务器接收请求的处理流程进行了介绍,接下来将结合流程图和代码分别对状态机和服务器解析请求报文进行详解。 流程图部分,描述主、从状态机调用关系与状态转移过程。 代码部分&#xff…

内 网 优 化

拓扑 需求 1)所有部门中都使用了网关冗余技术,为了增强网关稳定性和冗余性 -配置VRRP -SW5是VLAN10和VLAN20的Master ,是VLAN30的Backup -SW6是VLAN10和VLAN20的Backup,是VLAN30的Master 2)交换机之间存在很多冗余链路,必须防止环…

AtcoderABC253场

A - Median?A - Median? 题目大意 给定三个整数a、b和c&#xff0c;判断b是否是这些整数的中位数。 思路分析 判断升序降序两种情况 时间复杂度分析 O(1) 代码 #include<iostream> using namespace std; int main() { int a,b,c; cin>>a>>b>>…

Non-Local Video Denoising by CNN

摘要 Non-local patch based methods were until recently state-of-the-art for image denoising but are now outper formed by CNNs. Y et they are still the state-of-the-art for video denoising, as video redundancy is a key factor to attain high denoising perfor…

JavaWeb——Cookie和Session的工作流程

目录 一、定义 1、Cookie定义 2、Session 二、Cookie和Session的联系和区别 1、联系 2、区别 一、定义 1、Cookie定义 Cookie是浏览器在本地存储数据的一种机制&#xff0c;来自于服务器。 服务器在响应中会带有Set-Cookie字段&#xff0c;通过这个字段就可以把要保存在浏…

及早识别面肌痉挛症状,科学治疗是关键!

随着现代社会的快节奏生活和各种压力的增加&#xff0c;面肌痉挛这一神经肌肉紊乱性疾病的发病率也逐渐上升。面肌痉挛是指由于面肌肌肉群异常收缩而导致的面部肌肉抽搐和不自主运动的症状。如果不及早识别和治疗&#xff0c;将对患者的生活质量产生严重影响。因此&#xff0c;…

C语言,封装自定义函数

1、封装自定义函数&#xff0c;计算数组的最大和&#xff0c;最大差 //第一数组 #include <stdio.h> #include <string.h> int MaxSum(int len,int arr[]); int MaxDel(int len,int arr[]); int main(int argc, const char *argv[]) {int arr[]{5,6,8,51,31,51,88…

2023 7.10~7.16 周报 (RTM研究与正演的Python复现)

0 上周回顾 上周简单阅读了论文《Deep-Learning Full-Waveform Inversion Using Seismic Migration Images》, 但是并没读完…因为这篇论文中提到一个技术吸引了注意力: RTM (Reverse-time migration) 于是计划下周去专门熟悉熟悉RTM的机制, 并且试着用Python复现这个操作. 另…

数据处理 | Matlab实现Lichtenberg算法的机器学习数据选择

文章目录 效果一览基本介绍源码设计参考资料效果一览 基本介绍 Matlab实现Lichtenberg算法的机器学习数据选择 Lichtenberg算法适用于回归和分类数据集,并根据数量和最大覆盖范围选择最佳算法。Lichtenberg算法(Lichtenberg algorithm,LA)是由Pereira等人于2021年提出的一种…

Python爬虫——urllib_下载

urlretrieve(url&#xff0c; filename)函数 url 代表的是下载的路径 filename文件的名字 下载网页: url_page "http://www.baidu.com" urllib.request.urlretrieve(url_page, baidu.html)下载图片: url_img "https://img0.baidu.com/it/u2751401762,34216…