Java设计模式-适配器模式

目录

一、生活中的适配器例子

二、基本介绍

三、工作原理

四、类适配器模式

(一)类适配器模式介绍

(二)应用实例 

(三)类适配器模式注意事项和细节

五、对象适配器模式

(一)对象适配器模式介绍

(二)对象适配器模式应用实例

(三)对象适配器模式注意事项和细节

六、接口适配器模式

(一)接口适配器模式介绍

(二)接口适配器模式应用实例

(三)适配器模式的注意事项和细节

七、适配器模式在SpringMVC框架应用的源码剖析


一、生活中的适配器例子

泰国插座用的是两孔的(欧标),可以买个 多功能转换插头 ( 适配器 ) ,这样就可以使用了

二、基本介绍

  1. 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
  2. 适配器模式属于结构型模式
  3. 主要分为三类:类适配器模式、对象适配器模式、接口适配器模式

三、工作原理

  1. 适配器模式:将一个类的接口转换成另一种接口.原本接口不兼容的类可以兼容
  2. 从用户的角度看不到被适配者,是解耦的
  3. 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
  4. 用户收到反馈结果,感觉只是和目标接口交互,如图

四、类适配器模式

(一)类适配器模式介绍

基本介绍: Adapter 类,通过继承 src 类,实现 dst 类接口,完成 src->dst 的适配。

(二)应用实例 

1)应用实例说明
以生活中充电器的例子来讲解适配器,充电器本身相当于 Adapter 220V 交流电相当于src ( 即被适配者 ) ,我们的目 dst( 即 目标 ) 5V 直流电
2) 类图

3)代码实现 

被适配的类

//被适配的类
public class Voltage220V {
	//输出220V的电压
	public int output220V() {
		int src = 220;
		System.out.println("电压=" + src + "伏");
		return src;
	}
}

适配器类

//适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {

	@Override
	public int output5V() {
		// TODO Auto-generated method stub
		//获取到220V电压
		int srcV = output220V();
		int dstV = srcV / 44 ; //转成 5v
		return dstV;
	}

}

适配接口

//适配接口
public interface IVoltage5V {
	public int output5V();
}

手机类,有一个充电方法,参数为适配接口

public class Phone {

	//充电
	public void charging(IVoltage5V iVoltage5V) {
		if(iVoltage5V.output5V() == 5) {
			System.out.println("电压为5V, 可以充电~~");
		} else if (iVoltage5V.output5V() > 5) {
			System.out.println("电压大于5V, 不能充电~~");
		}
	}
}

创建手机进行充电

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(" === 类适配器模式 ====");
		Phone phone = new Phone();
		phone.charging(new VoltageAdapter());
	}

}

三)类适配器模式注意事项和细节

  1. Java是单继承机制,所以类适配器需要继承src类这一点算是一个缺点, 因为这要求dst必须是接口,有一定局限性;
  2. src类的方法在Adapter中都会暴露出来,也增加了使用的成本。
  3. 由于其继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增强了。

五、对象适配器模式

(一)对象适配器模式介绍

  1. 基本思路和类的适配器模式相同,只是将Adapter类作修改,不是继承src类,而是持有src类的实例,以解决兼容性的问题。 即:持有 src类,实现 dst 类接口, 完成src->dst的适配
  2. 根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系。
  3. 对象适配器模式是适配器模式常用的一种

(二)对象适配器模式应用实例

以生活中充电器的例子来讲解适配器,充电器本身相当于 Adapter 220V 交流电相当于src ( 即被适配者 ) ,我们的目 dst( 即目标 ) 5V 直流电,使用 对象适配器模 式完成

 被适配的类

//被适配的类
public class Voltage220V {
	//输出220V的电压
	public int output220V() {
		int src = 220;
		System.out.println("电压=" + src + "伏");
		return src;
	}
}

适配器类

//适配器类
public class VoltageAdapter  implements IVoltage5V {

	private Voltage220V voltage220V; // 关联关系-聚合
	
	
	//通过构造器,传入一个 Voltage220V 实例
	public VoltageAdapter(Voltage220V voltage220v) {
		
		this.voltage220V = voltage220v;
	}



	@Override
	public int output5V() {
		
		int dst = 0;
		if(null != voltage220V) {
			int src = voltage220V.output220V();//获取220V 电压
			System.out.println("使用对象适配器,进行适配~~");
			dst = src / 44;
			System.out.println("适配完成,输出的电压为=" + dst);
		}
		
		return dst;
		
	}

}

适配接口

//适配接口
public interface IVoltage5V {
	public int output5V();
}

手机类,有一个充电方法,参数为适配接口

public class Phone {

	//充电
	public void charging(IVoltage5V iVoltage5V) {
		if(iVoltage5V.output5V() == 5) {
			System.out.println("电压为5V, 可以充电~~");
		} else if (iVoltage5V.output5V() > 5) {
			System.out.println("电压大于5V, 不能充电~~");
		}
	}
}

创建手机进行充电

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(" === 类适配器模式 ====");
		Phone phone = new Phone();
		phone.charging(new VoltageAdapter());
	}

}

(三)对象适配器模式注意事项和细节

  1. 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口。
  2. 使用成本更低,更灵活。

 与类适配器对比,就是接口不继承被适配类了,而是直接持有被适配类对象(作为接口中的一个属性)

六、接口适配器模式

(一)接口适配器模式介绍

  1. 一些书籍称为:适配器模式(Default Adapter Pattern)或缺省适配器模式。
  2. 当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求
  3. 适用于一个接口不想使用其所有的方法的情况。

(二)接口适配器模式应用实例

Android 中的属性动画 ValueAnimator 类可以通过addListener(AnimatorListener listener) 方法添加监听器, 那么常规写法如下:
    ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
valueAnimator.addListener(new Animator.AnimatorListener(){
            @Override
            public void onAnimationStart (Animator animation){
            }
            @Override
            public void onAnimationEnd (Animator animation){
            }
            @Override
            public void onAnimationCancel (Animator animation){
            }
            @Override
            public void onAnimationRepeat (Animator animation){
            }
        }
    );
    valueAnimator.start();
有时候我们不想实现 Animator.AnimatorListener接口的全部方法, 我们只想监听onAnimationStart ,我们会如下写
    ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100);
valueAnimator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
//xxxx具体实现
        }
    });
    valueAnimator.start()
AnimatorListenerAdapter 类,就是一个接口适配器,代码如下: 它空实现了 Animator.AnimatorListener类 (src) 的所 有方法.。AnimatorListener是一个接口。
public static interface AnimatorListener {
    void onAnimationStart(Animator animation);
    void onAnimationEnd(Animator animation);
    void onAnimationCancel(Animator animation);
    void onAnimationRepeat(Animator animation);
}

==================================================
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener
Animator.AnimatorPauseListener {
    @Override //默认实现
    public void onAnimationCancel(Animator animation) {
    }
    @Override
    public void onAnimationEnd(Animator animation) {
    }
    @Override
    public void onAnimationRepeat(Animator animation) {
    }
    @Override
    public void onAnimationStart(Animator animation) {
    }
    @Override
    public void onAnimationPause(Animator animation) {
    }
    @Override
    public void onAnimationResume(Animator animation) {
    }
}
程序里的匿名内部类就是 Listener 具体实现类
new AnimatorListenerAdapter() {
    @Override
    public void onAnimationStart(Animator animation) {
        //xxxx具体实现
    }
}

(三)适配器模式的注意事项和细节

  1. 三种命名方式,是根据 src是以怎样的形式给到Adapter(在Adapter里的形式)来命名的。
  2. 类适配器:以类给到,在Adapter里,就是将src当做类  //继承
  3. 对象适配器:以对象给到,在Adapter里,将src作为一个对象 //持有
  4. 接口适配器:以接口给到,在Adapter里,将src作为一个接口 //实现
  5. Adapter模式最大的作用还是将原本不兼容的接口融合在一起工作。
  6. 实际开发中,实现起来不拘泥于我们讲解的三种经典形式

七、适配器模式在SpringMVC框架应用的源码剖析

SpringMvc 中的 HandlerAdapter, 就使用了适配器模式
SpringMVC 处理请求的流程
Spring 定义了一个适配接口,使得每一种 Controller 有一种对应的适配器实现类
适配器代替 controller 执行相应的方法
扩展 Controller 时,只需要增加一个适配器类就完成了 SpringMVC 的扩展了
可以看到处理器的类型不同,有 多重实现方式,那么调用方式就不是确定 的,如果需要直接调用
Controller 方法,需要调用的时候就得不断是使用 if else 来进行判断是哪一种子类然后执行。那么
如果后面要扩展 Controller ,就得修改原来的代码,这样违背了 OCP 原则。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【架构】ServerLess

文章目录 概述什么是serverless无服务与传统模式架构区别serverless优缺点使用serverless的应用场景有哪些“无服务器”搭建网站Serverless的落地案例来源 概述 架构 单体(三层架构)微服务分布式ServerLess 什么是serverless无服务 serverless中文的…

鸿蒙开发语言介绍--ArkTS

1.编程语言介绍 ArkTS是HarmonyOS主力应用开发语言。它在TypeScript (简称TS)的基础上,匹配ArkUI框架,扩展了声明式UI、状态管理等相应的能力,让开发者以更简洁、更自然的方式开发跨端应用。 2.TypeScript简介 自行补充TypeScript知识吧。h…

深入理解Python的logging模块:从基础到高级

在Python编程中,日志记录是一种重要的调试和错误追踪工具。Python的logging模块提供了一种灵活的框架,用于发出日志消息,这些消息可以被发送到各种输出源,如控制台、文件、HTTP GET/POST位置等。本文将深入探讨Python的logging模块…

冒泡排序之C++实现

描述 冒泡排序算法是一种简单的排序算法,它通过将相邻的元素进行比较并交换位置来实现排序。冒泡排序的基本思想是,每一轮将未排序部分的最大元素逐个向右移动到已排序部分的最右边,直到所有元素都按照从小到大的顺序排列。 冒泡排序的算法…

前端工程注入版本号

文章目录 一、前言二、webpack三、vite四、最后 一、前言 容器化时代,当页面出现问题时,如果你的新版本有可能已经修复了,那样你再排查它就没有意义了。为什么不一定是最新版本呢?一是可能是缓存作祟,二是可能运维成员…

每日一题——LeetCode860

个人方法: 用change数组保存我们拥有的零钱的数量,change数组只有change[5]、change[10]、change[20]是有效的,其值代表了不同面值的零钱拥有多少张 顾客付了多少钱,先把钱存入零钱数组,然后计算需要找零的金额&…

HarmonyOS - 鸿蒙开发入门

文章目录 HarmonyOS核心资源特性:全场景终端HarmonyOS 版本 HarmonyOS 和 OpenHarmony教程资源开发环境开发工具 - DevEco开发语言 - ArkTS核心框架 - ArkUI 考证 HarmonyOS 开发交流秋秋群:23458659,V : ez-code,期待交流和合作 …

vue 实验报告8 基于Nuxt.js开发一个Vue程序,实现登录和注册切换

一、步骤: 保证node.js版本在14以上 1. 全局安装create-nuxt-app: npm install -g create-nuxt-app2.9.x 2. 创建项目: create-nuxt-app my-nuxt-demo 选项这么选: 然后输入: cd my-nuxt-demo 3. 创建登录和注册页面: 在/pages目录下创建logi…

Docker知识总结

Docker 学习目标: 掌握Docker基础知识,能够理解Docker镜像与容器的概念 完成Docker安装与启动 掌握Docker镜像与容器相关命令 掌握Tomcat Nginx 等软件的常用应用的安装 掌握docker迁移与备份相关命令 能够运用Dockerfile编写创建容器的脚本 能够…

【小沐学写作】Docsify制作在线电子书、技术文档(Docsify + Markdown + node)

文章目录 1、简介2、安装2.1 node2.2 docsify-cli 3、配置3.1 初始化3.2 预览效果3.3 加载对话框3.4 更多页面3.5 侧 栏3.6 自定义导航栏 结语 1、简介 https://docsify.js.org/#/?iddocsify 一个神奇的文档网站生成器。 简单轻巧没有静态构建的 html 文件多个主题 Docsify…

跨平台Markdown编辑软件Typora mac功能介绍

Typora mac是一款跨平台的Markdown编辑器,支持Windows、MacOS和Linux操作系统。它具有实时预览功能,能够自动将Markdown文本转换为漂亮的排版效果,让用户专注于写作内容而不必关心格式调整。Typora Mac版除了支持常见的Markdown语法外&#x…

【测试开发】测试用例讲解

文章目录 目录 文章目录 前言 一、测试用例的基本要素 二、测试用例的设计方法 1.基于需求的设计方法 对日历根据web界面的功能布局分析出的功能框图如下: 继续举一个例子百度云盘非功能测试的案例: 2.等价类 3.边界值 5.正交表 6.场景设计法 7…

leetcode 268. 丢失的数字(优质解法)

链接&#xff1a;268. 丢失的数字 代码: class Solution {public int missingNumber(int[] nums) {int result0;for(int i0;i<nums.length;i){result^i;}for(int i0;i<nums.length;i){result^nums[i];}return result;} } 题解&#xff1a; 本题是比较简单的题&#xff…

c语言:递归法求n的阶乘|练习题

一、题目 输入一个数n&#xff0c;用递归法求n的阶乘 二、思路分析 1、因为n!(n-1)!*n,所以&#xff0c;可以选择用递归法 三、代码截图【带注释】 四、源代码【带注释】 #include <stdio.h> //思路&#xff1a; //因为n!(n-1)!*n,所以&#xff0c;可以选择用递归法 int…

数据资源工具断点续传及下载重试功能

我们可以利用数据资源工具下载各类卫星及矢量数据&#xff0c;具体方法见&#xff1a;Sentinel-2 下载&#xff08;其它数据操作方式类似&#xff09;&#xff0c;但在使用资源工具下载数据时可能会出现由于网络不稳定&#xff0c;网站关闭连接而造成下载的错误或中断。尤其是下…

微信小程序图片压缩原来这么easy!

前言 在日常业务中我们可能会涉及到图片上传功能&#xff0c;现代影像设备大多数的照片都是几MB&#xff0c;甚至几十MB大小&#xff0c;大文件的上传会导致上传进度缓慢、占用云存储空间。所以&#xff0c;我们会根据需求来做图片压缩&#xff0c;将过大的图片文件压缩到指定…

线性回归简介

线性回归简介 1、情景描述2、线性回归 1、情景描述 假设&#xff0c;我们现在有这么一张图&#xff1a; 其中&#xff0c;横坐标x表示房子的面积&#xff0c;纵坐标y表示房价。我们猜想x与y之间存在线性关系&#xff1a; y k x b ykxb ykxb 现在&#xff0c;思考一个问题&…

期末加油站-图像处理期末知识点汇总

第三章&#xff1a;图像增强 一、概念 1.图像增强是通过某种技术有选择地突出对某一具体应用有用的信息&#xff0c;削弱或抑制一些无用的信息。 2. 图像增强处理不是无损处理&#xff0c;不能增加原图像的信息。 3. 图像增强按所处理的对象不同可分为&#xff1a; 灰度图像增…

腾讯面试:SaaS多租户,如何设计?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业网易、美团、字节、如阿里、滴滴、极兔、有赞、希音、百度、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 多租户设计&#xff0c;如何 技术选型&#xff…
最新文章