适配器模式定义
系统需用用到原有的类的功能,但是原有的类不符合现在的系统接口规范,需要将原有的类改造成符合现在系统的接口规范,使得两个因为接口规范不能在一起工作的类能在一起工作。
适配器模式的关键类
目标接口(Target):当前系统所期待的接口,可以是接口或者抽象类。
适配者(Adaptee):不符合系统要求的类,需要对其进行改造,让它符合系统规范。
适配器(Adapter):它是一个转换类,通过继承或者引用适配者,将适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
适配器模式的种类
类适配器:主要是适配器继承适配者,然后实现目标接口,重写目标接口的相关方法,在重写的方法中调用适配者的方法。
对象适配器:适配器引用适配者,适配器实现目标接口,重写目标接口的相关方法,在重写的方法中调用适配者的方法。
对象适配器相比类适配器更加灵活,因为对象适配器中可以引用不同的适配者。
适配器模式的好处
在不改变适配者类结构的情况下,就能让适配者的功能得到复用。
让适配者和客户端解耦,客户端拿到了自己想要的功能,而不需要知道这个功能是通过适配器调用适配者得到的。
适配器模式结构示意图
类适配器模式(adapter pattern)结构图:
对象适配器模式(object adapter pattern)结构图:
适配者应用举例
spring MVC中的适配器模式
Spring MVC中的适配器模式主要用于执行目标 Controller 中的请求处理方法。
在Spring MVC中,DispatcherServlet 作为用户,HandlerAdapter 作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller 作为需要适配的类。
为什么要在 Spring MVC 中使用适配器模式?Spring MVC 中的 Controller 种类众多,不同类型的 Controller 通过不同的方法来对请求进行处理。如果不利用适配器模式的话,DispatcherServlet 直接获取对应类型的 Controller,需要的自行来判断,像下面这段代码一样:
if(mappedHandler.getHandler() instanceof MultiActionController){
((MultiActionController)mappedHandler.getHandler()).xxx
}else if(mappedHandler.getHandler() instanceof XXX){
...
}else if(...){
...
}
这样假设如果我们增加一个 HardController,就要在代码中加入一行 if(mappedHandler.getHandler() instanceof HardController),这种形式就使得程序难以维护,也违反了设计模式中的开闭原则 – 对扩展开放,对修改关闭。
public interface HandlerAdapter {
boolean supports(Object var1);
ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);
}
现该接口的适配器每一个 Controller
都有一个适配器与之对应,这样的话,每自定义一个 Controller
需要定义一个实现 HandlerAdapter
的适配器。
springmvc 中提供的 Controller
实现类有如下
springmvc 中提供的 HandlerAdapter
实现类如下
来看一下SimpleControllerHandlerAdapter适配器 是如何处理请求的
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
当Spring容器启动后,会将所有定义好的适配器对象存放在一个List集合中,当一个请求来临时,DispatcherServlet 会通过 handler 的类型找到对应适配器,并将该适配器对象返回给用户,然后就可以统一通过适配器的 hanle() 方法来调用 Controller 中的用于处理请求的方法
public class DispatcherServlet extends FrameworkServlet {
private List<HandlerAdapter> handlerAdapters;
//初始化handlerAdapters
private void initHandlerAdapters(ApplicationContext context) {
//..省略...
}
// 遍历所有的 HandlerAdapters,通过 supports 判断找到匹配的适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
}
// 分发请求,请求需要找到匹配的适配器来处理
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
// 确定当前请求的匹配的适配器.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
ha.getLastModified(request, mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
// ...省略...
}
通过适配器模式我们将所有的 controller
统一交给 HandlerAdapter
处理,免去了写大量的 if-else
语句对 Controller
进行判断,也更利于扩展新的 Controller
类型。