持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
前言
适配器模式应用非常广泛,我们生活中很多事物都使用了适配器模式,比如生活中常见的手机充电的场景,我们都知道家庭中插座电压是220V,但是我们手机数据线上标注的却是5V-3A、10V-4A,那么手机是如何从220V的电压中充电的呢?关键就是那个充电头充当了适配器的模式,将电压转换为手机能承受的小电压,适配器模式也是这样的原理。
适配器模式工作原理
- 将一个类的接口转换成另一种接口,让原本接口不兼容的类可以兼容
- 从用户的角度看不到被适配者,是解耦的
- 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
- 用户收到反馈结果,感觉只是和目标接口交互。
适配器模式实现
适配器模式有三种比较常见的实现方式:
- 类适配器模式
- 对象适配器模式
- 接口适配器模式
类适配器模式
简单来说就是Adapter类通过继承src类,实现dst接口完成src到dst的适配。
src类定义源220V输出电压
public class Voltage220V {
public int OutPut220(){
int src = 220;
System.out.println("输出电压220");
return src;
}
}
dst定义接口输入5v电压
interface Voltage5V {
public int OutPut5();
}
Adapter继承src,实现dst
public class VoltageAdapter extends Voltage220V implements Voltage5V{
@Override
public int OutPut5() {
int src = OutPut220();
int dst = src/44;
System.out.println("适配器转为5V");
return dst;
}
}
手机调用dst接口输入5v方法进行充电,实际上调用的是Adaoter类中实现dst的output5()方法。
public class Phone {
public void Charge(Voltage5V voltage5V){
int dst = voltage5V.OutPut5();
System.out.println("5V充电");
}
}
总结:
- Java是单继承机制,反以类适配器需要继承src类这一点算是一个缺点,因为这要求dst必须是接口,有一定局限性;
- src类的方法在Adapter中都会暴露出来,也增加了使用的成本。
- 由于其继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增强了。
对象适配器模式
基本思路和类的适配器模式相同,只是将Adapter类作修改,不是继承src类,而是持有src类的实例,切解决兼容性的问题。即:持有src类,实现 dst 类接口,完成src->dst的适配。
在Adapter类中,不再继承src,而是创建Voltage220V实例对象
public class VoltageAdapter implements Voltage5V {
private Voltage220V voltage220V;
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int OutPut5() {
int src = voltage220V.OutPut220();
int dst = src/44;
System.out.println("适配器转为5V");
return dst;
}
}
对象适配器和类适配琴其实算是同一种思想,只不过实现方式不同。 根据合成复用原则,使用组合替代继承,所以它解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口。使用成本更低,更灵活。
接口适配器模式
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
接口定义方法
public interface test {
public void m1();
public void m2();
public void m3();
public void m4();
}
抽象类为接口中的方法提供空实现
public abstract class testAdapter implements test{
public void m1(){}
public void m2(){}
public void m3(){}
public void m4(){}
}
使用时针对需要的方法进行实现
public class Client {
public static void main(String[] args) {
testAdapter adapter = new testAdapter(){
public void m1(){
System.out.println("实现m1方法");
}
};
adapter.m1();
}
}
接口适配器模式适用于不需要src所有方法的场景。
手写SpringMVC中的适配器
首先回顾一下SpringMVC的工作原理:
- 用户发送请求至前端控制器DispatcherServlet。
- DispatcherServlet收到请求调用HandlerMapping处理器映射器。
- 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet.
- DispatcherServlet调用HandlerAdapter处理器适配器。
- HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
- Controller执行完成返回ModelAndView。
- HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
- ViewReslover解析后返回具体View。
- DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。
要想手写适配器处理流程,首先需要了解类图
请求到达DispatchServlet,DispatchServlet需要根据请求选择对应的处理器适配器也就是HandlerAdapter,处理器适配器调用对应的处理器Controller。
定义Controller接口,多种Controller实现Controller接口,实现自己的方法。
//多种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...");
}
}
定义HandleAdapter,根据Controller实现对应的适配器
///定义一个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);
}
}
DispatchServlet进行分发
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());
}
//适配器分配
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);
}
public HandlerAdapter getHandler(Controller controller) {
//遍历:根据得到的controller(handler), 返回对应适配器
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(controller)) {
return adapter;
}
}
return null;
}
public static void main(String[] args) {
new DispatchServlet().doDispatch(); // http...
}
}