适配器模式----------设计模式
最近在看SpringMVC源码,从中看到了比较优秀的设计模式所以来分享下。

1.适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作
具体的详细知识可以参考这篇文章

http://haolloyin.blog.51cto.com/1177454/346128

http://blog.csdn.net/xtu_xiaoxin/article/details/8796499

适用场景:

1、已经存在的类的接口不符合我们的需求;

2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;

3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。

2.SpringMvc中的适配器(HandlerAdapter)
SpringMVC中的适配器到底是解决以上哪个问题的呢?我们来一步一步看看源码,看看Spring是怎么做的

首先我们找到前端控制器DispatcherServlet可以把它理解为适配器模式中的Client,它的主要作用在于通过处理映射器(HandlerMapper)来找到相应的Handler(即Controlle(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)r),并执行Controller中相应的方法并返回ModelAndView,

mappedHandler.getHandler()其实就是通过Spring容器中获取到的(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)Controller

先短暂回顾下流程

1.DispatcherServlet中的doDispatch

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
ModelAndView mv = null;
Exception dispatchException = null; try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request); // 此处通过HandlerMapping来映射Controller
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // 获取适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
} if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // 通过适配器调用controller的方法并返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) {
return;
} applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

2.为什么要使用适配器模式呢?
Controller可以理解为Adaptee(被适配者)其中之一

可以看到处理器(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用Controller方法,需要调用的时候就得不断是使用if else来进行判断是哪一种子类然后执行。那么如果后面要扩展(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)Controller,就得修改原来的代码,这样违背了开闭原则(对修改关闭,对扩展开放)。

3.SpringMvc 是如何使用适配器模式来解决以上问题的呢?
Spring创建了一个适配器接口(HandlerAdapter)使得每一种处理器(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)有一种对应的适配器实现类,让适配器代替(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)执行相应的方法。这样在扩展Controller 时,只需要增加一个适配器类就完成了SpringMVC的扩展了

 public interface HandlerAdapter {

 boolean supports(Object handler);

 ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

 }

supports()方法传入处理器(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)判断是否与当前适配器支持如果支持则从DispatcherServlet中的HandlerAdapter实现类中返回支持的适配器实现类。handler方法就是代理Controller来执行请求的方法并返回结果。
在DispatchServlert中的doDispatch方法中

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

此代码通过调用DispatchServlert 中getHandlerAdapter传入Controller(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等),来获取对应的HandlerAdapter 的实现子类,从而做到使得每一种Controller有一种对应的适配器实现类

返回后就能通过对应的适配实现类代理Controller(宽泛的概念Controller,以及HttpRequestHandler,Servlet,等等)来执行请求的方法

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

其中一个处理器适配器就是我们常说的最熟悉的Controller类适配器

---------------------
作者:_PPB
来源:CSDN
原文:https://blog.csdn.net/u010288264/article/details/53835185
版权声明:本文为博主原创文章,转载请附上博文链接!

Sping 里面的适配器模式的实现的更多相关文章

  1. PHP设计模式(七)适配器模式(Adapter For PHP)

    适配器模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作. 如下图(借图): // 设置书的接口 // 书接口 interface BookI ...

  2. 《JS设计模式笔记》 5,适配器模式

    //适配器模式的作用就像一个转接口. jQuery("#"+id); $id=function (id) { return jQuery("#"+id)[0]; ...

  3. 设计模式(七): 通过转接头来观察"适配器模式"(Adapter Pattern)

    在前面一篇博客中介绍了“命令模式”(Command Pattern),今天博客的主题是“适配器模式”(Adapter Pattern).适配器模式用处还是比较多的,如果你对“适配器模式”理解呢,那么自 ...

  4. 设计模式(七)适配器模式(Adapter Pattern)

    一.引言 在实际的开发过程中,由于应用环境的变化(例如使用语言的变化),我们需要的实现在新的环境中没有现存对象可以满足,但是其他环境却存在这样现存的对象.那么如果将“将现存的对象”在新的环境中进行调用 ...

  5. PHP 适配器模式

    适配器模式(Adapter)模式:将一个类的接口,转换成客户期望的另一个类的接口.适配器让原本接口不兼容的类可以合作无间.     [适配器模式中主要角色]目标(Target)角色:定义客户端使用的与 ...

  6. 每天一个设计模式-3 适配器模式(Adapteer)

    每天一个设计模式-3 适配器模式(Adapteer) 1.现实中的情况 旧式电脑的硬盘是串口的,直接与硬盘连接,新硬盘是并口的,显然新硬盘不能直接连在电脑上,于是就有了转接线.好了,今天的学习主题出来 ...

  7. 设计模式--适配器模式Adapter(结构型)

    一.适配器模式 适配器模式的主要作用是在新接口和老接口之间进行适配.将一个类的接口转换成客户端期望的另外一个接口.其实适配器模式有点无赖之举,在前期设计的时候,我们就不应该考虑适配器模式,而应该通过重 ...

  8. c#设计模式-适配器模式

    一. 适配器(Adapter)模式 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作. 名称由来 这很像变压器(Adapter),变压 ...

  9. C#设计模式系列:适配器模式(Adapter)

    在实际的软件系统设计和开发中,为了完成某项工作需要购买一个第三方的库来加快开发.这带来一个问题,在应用程序中已经设计好的功能接口,与这个第三方提供的接口不一致.为了使得这些接口不兼容的类可以在一起工作 ...

随机推荐

  1. Xcode: Run Script 的运用, 使build打包后自动+1

    背景: 每次打包都要build+1处理,比较麻烦,使用 Run Script 的运用使build打包后自动+1 0. 使用xcode 添加run Script 然后就可以添加Run Script了 1 ...

  2. Divisibility by 25 CodeForces - 988E (技巧的暴力)

    You are given an integer nn from 11 to 10181018 without leading zeroes. In one move you can swap any ...

  3. 【刷题】【LeetCode】总

    参考资料 用动画的形式呈现解LeetCode题目的思路 目录: 000-十大经典排序算法 001-两数之和-easy 暴力法(遍历):两遍哈希表:一遍哈希表 002- 003- 004- 005- 0 ...

  4. 深度学习识别CIFAR10:pytorch训练LeNet、AlexNet、VGG19实现及比较(二)

    版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com AlexNet在2012年ImageNet图像分类任务竞赛中获得冠军.网络结构如下图所示: 对CIFA ...

  5. CLOUD配置审批流发消息

    1.进入流程中心-工作流-流程设计中心 2.新增物料管理冻结流程 3.进入修改配置项 4.新消息节点 5.写入消息标题,内容等 6.填入接收人 7.保存后发布 8.进入流程配置中心 9.捆绑并启用 1 ...

  6. 汉诺塔I && II

    汉诺塔I 题目链接:https://www.nowcoder.com/questionTerminal/7d6cab7d435048c4b05251bf44e9f185 题目大意: 略 分析: 利用汉 ...

  7. 关于Oracle使用管理员账号登录失败的问题

    我在本地建的Oracle数据库在调试自己写的存储过程的时候提示缺少 debug connect session 权限,一般情况下根据这个提示直接用管理员账号登录进去,执行 grant debug co ...

  8. Python——SQL——将查询的数据列表化

    sql = 'select paihao from yang1.cailiaopai' data = datebase.shujuku.sj_select(sql) #将获得的数据进行列表化 data ...

  9. Azure Function & AWS Function With C#

    Using C# with Azure Functions Two important prerequisites need to be met to build Azure Functions ap ...

  10. magento 2 method config

    1. 模板渲染静态文件: <?php echo $this->getViewFileUrl('requirejs::require.js'); ?> 2.