java设计模式---- 适配器模式,手写SpringMVC适配器设计模式

2023-11-01

主文章(所有java设计模式的目录)
https://blog.csdn.net/grd_java/article/details/122252696
源码位置
码云:https://gitee.com/yin_zhipeng/design_mode.git
GitHub:
学习设计模式前必须知道的东西
  1. 看待设计模式,要站在更大的角度(代码重用性、可读性、可扩展性、可靠性、程序高内聚,低耦合)来综合考虑看待,而不是功能实现的角度看待,不要觉得实现一个功能没必要这么麻烦
  1. 文章中给出的设计模式类图都是标准的实现方式,并不一定要完全遵守标准,所以只要设计思想符合,一个设计模式有多种实现方式,尤其是看别人源码的时候,不要用标准类图死扣

1. 适配器模式(Adapter Pattern)

  1. 又名缺省适配器模式,将某个类的接口转换为客户端期望的另一个接口表示,主目的是兼容性,让原本接口不匹配不能一起工作的两个类,可以协同工作。别名为包装器(Wrapper)
  2. 适配器模式属于结构型模式
  3. 分三类:类适配器、对象适配器、接口适配器模式
  4. 通俗的讲就是将一个对象,通过不同适配器,转换为不同的对象,比如220V市电,通过各种变压器,转换为不同直流电
工作原理
  1. 适配器模式:将一个类的接口转换成另一种接口,让原本接口不兼容的类可以兼容
  2. 用户角度看不到被适配者,是解耦的
  3. 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
  4. 用户收到反馈结果,感觉只是和目标接口交互
    在这里插入图片描述

1. 类适配器

  1. Adapter类(适配器),继承src类(源类),实现dst类接口(目标),完成src->dst的适配
  2. 假设src就是墙上的插座,220v交流电。dst,是目标,比如手机,我们需要5v直流电
  3. 那么Adapter就是充电器,将220v交流电适配为5v直流电,给手机使用
    在这里插入图片描述
注意事项
  1. java是单继承机制,类适配器需要继承源类这一点是一个缺点(如果我们将适配器也抽象成一个接口,然后传入具体实现类指定适配器是否可行呢?也OK)
  2. 源类,会在类适配器中暴露出来,增加使用成本
  3. 不过继承了源类,根据需求,重写源类方法,灵活性反而增强了
类图:com/yzpnb/design_mode/adapter_pattern/class_adapter/uml/Phone.puml

在这里插入图片描述

代码:com/yzpnb/design_mode/adapter_pattern/class_adapter/phone包下
  1. 220V市电,源对象,很多产品不能直接使用它
    在这里插入图片描述
  2. 5V直流电,目标对象,手机充电时可以使用的对象(不做具体实现,适配器将其转换)
    在这里插入图片描述
  3. 适配器,继承220V类,我们直接可以获取它,实现5V接口,接口中规定我们要将220V适配成什么样
    在这里插入图片描述
  4. 有了适配器,就可以给手机充电了
    在这里插入图片描述
  5. 使用者,我们需要先选择充电器,然后给手机充电
    在这里插入图片描述

2. 对象适配器(常用)

  1. 和类适配器基本相同,对适配器类做了一些修改
  2. 适配器类不再继承源类了,而是持有源类的实例,解决兼容性问题
  3. 也就是持有src类,实现dst类接口,完成src->dst的适配
  4. 根据“合成复用原则”,系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式
类图:com/yzpnb/design_mode/adapter_pattern/object_adapter/uml/Phone.puml

在这里插入图片描述

代码:com/yzpnb/design_mode/adapter_pattern/object_adapter/phone包下
  1. 修改适配器类
    在这里插入图片描述
  2. 其它都无需变动
    在这里插入图片描述

3. 接口适配器

  1. 不需要去全部实现接口提供的方法时,可以设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类就可以有选择地覆盖父类的某些方法来实现需求
  2. 适用与一个接口不想使用其所有的方法的情况
  3. 更加抽象的概念了,连适配器类都不需要了
程序:com/yzpnb/design_mode/adapter_pattern/interface_adapter/phone包下
  1. 假设我在5V的接口中,添加两个方法,漏电和停电
    在这里插入图片描述
  2. 抽象类,继承,空实现方法,这样其他类就可以有选择的使用这些方法
    在这里插入图片描述
  3. 需要使用某些方法的类,直接继承实现,或者使用匿名内部类
    在这里插入图片描述

2. 用到适配器模式的源码

Spring MVC的HandlerAdapter,使用到了适配器模式
  1. 使用HandlerAdapter的原因是,处理器类型不同,有多重实现方式,调用方法是不确定的,若直接调用Controller方法,需要调用的时候就得不断使用if else进行判断是哪一子类,如果后面要扩展Controller,就得修改原来代码,违背OCP(开闭)原则
  2. 先看一下SpringMVC请求Controller流程,类图:com/atguigu/spring/UML/SpringMVC请求流程.puml
    在这里插入图片描述
  3. 如何使用适配器模式的呢?(实在不想画这张类图了,太麻烦了)
  1. 进入DispatcherServlet
    在这里插入图片描述
  1. MVC使用doDispatch方法处理来到的请求,然后通过getHandler方法,获取我们请求的Handler,拿到控制器(mappedHandler映射Controller)
    在这里插入图片描述
  1. 拿到控制器(Controller映射)后,通过getHandlerAdapter方法获取相符合的适配器(不同的Handler,需要不同的适配器去调用相关方法)
    在这里插入图片描述
  1. 先看看getHandlerAdapter怎么返回的,最后再看看返回的到底是什么
    在这里插入图片描述
  1. 发现是一个for循环,依次遍历所有适配器,然后通过supports()方法判断,是否是一个类型,如果是就是返回适配器
    在这里插入图片描述
    在这里插入图片描述
  1. HandlerAdapter接口,看看具体有哪些适配器
    在这里插入图片描述
  1. 拿到适配器后,又干了什么呢?原来是通过适配器,调用handle方法,返回ModelAndView(通过适配器调用controller的方法)。
    在这里插入图片描述

3. 手写SpringMVC适配器设计模式,获取对应Controller

  1. Spring 定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类
  2. 适配器代替controller执行相应的方法
  3. 扩展Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展了
类图:com/atguigu/spring/springmvc/uml/springmvc.puml

在这里插入图片描述

  1. 好处,如果我们添加一个Controller种类,添加一个对应适配器种类,对于我们使用的DispatchServlet,没有任何影响
代码:com/atguigu/spring/springmvc包下
  1. 先把需要适配的东西Controller高出来(Controller是5V直流电,我们想要适配成这个样子)
    在这里插入图片描述
//多种Controller实现  
public interface Controller {

}
//不同的适配种类
class HttpController implements Controller {
	public void doHttpHandler() {
		System.out.println("http...");
	}
}

class SimpleController implements Controller {
	public void doSimplerHandler() {
		System.out.println("simple...");
	}
}

class AnnotationController implements Controller {
	public void doAnnotationHandler() {
		System.out.println("annotation...");
	}
}

  1. 把适配器搞出来(就是充电器),有多种适配器
    在这里插入图片描述
///定义一个Adapter接口 
public interface HandlerAdapter {
	public boolean supports(Object handler);

	public void handle(Object handler);
}

// 多种适配器类
class SimpleHandlerAdapter implements HandlerAdapter {

	public void handle(Object handler) {
		((SimpleController) handler).doSimplerHandler();
	}

	public boolean supports(Object handler) {
		return (handler instanceof SimpleController);
	}

}

class HttpHandlerAdapter implements HandlerAdapter {

	public void handle(Object handler) {
		((HttpController) handler).doHttpHandler();
	}

	public boolean supports(Object handler) {
		return (handler instanceof HttpController);
	}

}

class AnnotationHandlerAdapter implements HandlerAdapter {

	public void handle(Object handler) {
		((AnnotationController) handler).doAnnotationHandler();
	}

	public boolean supports(Object handler) {

		return (handler instanceof AnnotationController);
	}

}
  1. DispatchServlet
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
import java.util.ArrayList;
import java.util.List;

public class DispatchServlet {

	//保存了所有适配器
	public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();

	//适配器放进去
	public DispatchServlet() {
		handlerAdapters.add(new AnnotationHandlerAdapter());
		handlerAdapters.add(new HttpHandlerAdapter());
		handlerAdapters.add(new SimpleHandlerAdapter());
	}

	//首先调用的就是doDispatch方法
	public void doDispatch() {

		// 此处模拟SpringMVC从request取handler的对象,
		// 适配器可以获取到希望的Controller
		 HttpController controller = new HttpController();
		// AnnotationController controller = new AnnotationController();
		//SimpleController controller = new SimpleController();
		// 得到对应适配器
		HandlerAdapter adapter = getHandler(controller);
		// 通过适配器执行对应的controller对应方法
		adapter.handle(controller);

	}

	//根据Controller获取适配器,SpringMVC中是映射对象mappedHandler
	public HandlerAdapter getHandler(Controller controller) {
		//遍历:根据得到的controller(handler), 返回对应适配器
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(controller)) {
				return adapter;
			}
		}
		return null;
	}

	//这里我们人为直接调用doDispatch()
	public static void main(String[] args) {
		new DispatchServlet().doDispatch(); // http...
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java设计模式---- 适配器模式,手写SpringMVC适配器设计模式 的相关文章

随机推荐

  • 【Java之多线程篇】——吐血整理Java多线程详解(知识点+代码)

    目录 线程基本概念 并行 并发的区别 多线程优点和何时使用多线程 多线程创建的两种方式 继承Thread类 实现Runnable接口 代码 Thread类中的常用方法 线程的生命周期 线程的同步 用线程同步解决线程安全问题的方式 一 同步代
  • 找工作的英文自我介绍

    找工作的英文自我介绍 Good morning It s my great honor to be here for this interview Now allow me to introduce myself briefly My na
  • python基础入门系列

    基础篇 一 python基础入门 二 python程序的编写运行 三 pycharm的安装使用 四 python的包管理 五 python的repl 提高篇 OpenCV学习 一 opencv python安装与初步认识 二 opencv对
  • Linux——网络基础概论

    网络基本概念 概念 网络是由若干结点和连接这些结点的链路组成 网络中的结点可以是计算机 交换机 路由器等设备 即将不同的终端设备连接起来 网络设备 路由器 网络层 集线器 物理层 交换机 数据链路层 网络线路 网线 双绞线100m 同轴电缆
  • IntelliJ IDEA2020安装使用(保姆级)

    IntelliJ IDEA安装使用 保姆级 文章目录 IntelliJ IDEA安装使用 保姆级 1 0 IntelliJ IDEA 介绍 1 1 IDEA 的主要优势 1 2 IDEA的下载地址 1 3 IDEA安装要求 1 3 1 JD
  • 机器人编程和编程有什么区别

    机器人编程和编程有什么区别 很多的家长在培养孩子的学习方面也可以说是相当的耐心的 他们会给孩子选择一些能够有利于孩子成长的课程 就拿现在很多的家长想要孩子去学习机器人编程的课程来说 有的家长对于机器人编程和编程有什么区别并不是很清楚 今天我
  • 网络安全-CDN绕过寻找真实IP

    网络安全 CDN绕过寻找真实IP CDN就是CDN加速 就是根据你的目标让你访问的更快 CDN CDN 即内容分发网络 主要解决因传输距离和不同运营商节点造成的网络速度性能低下的问题 说得简单点 就是一组在不同运营商之间的对接节点上的高速缓
  • bfs 模版

    player 队列q marked数组 dist数组 前驱pre数组 这里说数组指的是顶点是按0 V 1编好号的情况 如果没编号 就用一般的symbol table比如map unordered map 另外前驱一般情况是多个 即一般应该定
  • eclipse中在lib目录下添加或删除jar包,Referenced Libraries无法同步问题

    eclipse版本 myeclipse 9 0 以前用myeclipse 6 5的时候 在lib目录下添加或删除jar包 Referenced Libraries是可以同步的 现在换成myeclipse 9 0就不行了 只能在java bu
  • matlab读取excel文件详解

    MATLAB是一种十分强大的科学计算软件 不仅可以进行数值计算 矩阵运算 还可以处理Excel CSV和其他常见格式的数据 在现实生活中 Excel文件是非常常见的数据文件 它包含了各种信息 诸如数据记录 计算和预测等 MATLAB提供了一
  • 单链表的创建和添加元素(具体代码实现) [数据结构][Java]

    单链表的创建和添加元素 具体代码实现 具体代码如下 实现了单链表的创建和元素的添加 package com ffyc linkedlist public class SingleLinkedList 先初始化一个头结点 头结点不能动 头结点
  • gazebo仿真 机械臂抓取和放置 使用ros_control插件

    仿真截图 rqtgraph ROS Control教程官方 http gazebosim org tutorials tut ros control 下图概述了仿真 硬件 控制器和传输之间的关系 图片分 gazebo仿真 和真实硬件两部分
  • 使用weex,开发美食app之vue页面实现

    这里就带用weex大家做一个简单的app 数据接口来自 阿里云 https market aliyun com products 57126001 cmapi012028 html spm 5176 8216963 738024 10 mt
  • MixFormer: End-to-End Tracking with Iterative Mixed Attention解读

    MixFormer End to End Tracking with Iterative Mixed Attention 代码 文章 https github com MCG NJU MixFormer Abstract 跟踪通常采用特征提
  • root用户无法启动vscode的解决方法

    root用户无法启动vscode 的解决方法 1 vscode with root 2 解决方法 3 总结 1 vscode with root 今天切换到Ubuntu的root用户进行编码调试 发现VSCode一直无法打开 命令提示和网上
  • Failed to compile with 1 error。Syntax Error: Error: Loading PostCSS Plugin failed: Cannot find modul

    Syntax Error Error Loading PostCSS Plugin failed Cannot find module postcss pxtorem 错误 解决啦 方法 npm i postcss pxtorem 5 1
  • 使用 redux 有哪些原则?

    核心描述 单一数据源 整个应用的全局 state 被存储在一棵 object tree 中 并且这个 object tree 只存在于唯一一个 store 中 State 是只读的 唯一改变 state 的方法就是触发 action act
  • Java生成指定时间段的一个随机时间

    package com tsjsr util import java text SimpleDateFormat import java util Date import junit framework TestCase public cl
  • 数组应用: 找出一组数据中比均值大的数据并输出

    数组应用 找出一组数据中比均值大的数据并输出 问题描述 由键盘输入读取整型数据 数据数量不超过100个 当读取到数据 1时 停止读取数据 并计算这些数据的均值 不包含 1 将大于均值的数据输出 问题分析 给定了数据数量不超过100 若将每个
  • java设计模式---- 适配器模式,手写SpringMVC适配器设计模式

    主文章 所有java设计模式的目录 https blog csdn net grd java article details 122252696 源码位置 码云 https gitee com yin zhipeng design mode