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

主文章(所有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...
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值