适配器模式做的就是,有一个接口需要实现,但是我们现成的对象都不满足,需要加一层适配器来进行适配。适配器模式总体来说分三种:默认适配器模式、对象适配器模式、类适配器模式。那我们生活中很常见的一个例子来讲,比如你水龙头接口是4cm,而房间室内接入管道是10cm此时我们没法直接对接,就需要一个中间件来联通水龙头与管道这个过程就叫适配,水暖上名字称为大小头咳咳跑远了。
默认适配器模式:
首先,我们先看看最简单的适配器模式默认适配器模式(Default Adapter)是怎么样的。我们用 Appache commons-io 包中的 FileAlteration Listener 做例子,此接口定义了很多的方法,用于对文件或文件夹进行监控,一旦发生了对应的操作,就会触发相应的方法。
public interface FileAlterationListener {
void onStart(final FileAlterationObserver observer);
void onDirectoryCreate(final File directory);
void onDirectoryChange(final File directory);
void onDirectoryDelete(final File directory);
void onFileCreate(final File file);
void onFileChange(final File file);
void onFileDelete(final File file);
void onStop(final FileAlterationObserver observer);
}
此接口的一大问题是抽象方法太多了,如果我们要用这个接口,意味着我们要实现每一个抽象方法,如果我们只是想要监控文件夹中的文件创建和文件删除事件,可是我们还是不得不实现所有的方法,很明显,这不是我们想要的。所以,我们需要下面的一个适配器,它用于实现上面的接口,但是所有的方法都是空方法。这样,我们就可以转而定义自己的类来继承下面这个类即可。
public class FileAlterationListenerAdaptor implements FileAlterationListener {
public void onStart(final FileAlterationObserver observer) {
}
public void onDirectoryCreate(final File directory) {
}
public void onDirectoryChange(final File directory) {
}
public void onDirectoryDelete(final File directory) {
}
public void onFileCreate(final File file) {
}
public void onFileChange(final File file) {
}
public void onFileDelete(final File file) {
}
public void onStop(final FileAlterationObserver observer) {
}
}
比如我们可以定义以下类,我们仅仅需要实现我们想实现的方法就可以了:
public class FileMonitor extends FileAlterationListenerAdaptor {
public void onFileCreate(final File file) {
// 文件创建
doSomething();
}
public void onFileDelete(final File file) {
// 文件删除
doSomething();
}
}
当然,上面只是适配器模式的其中一种,也是最简单的一种平时工作中基本不会使用这种形式。
对象适配器模式:
public interface Duck {
public void quack(); // 鸭的呱呱叫
public void fly(); // 飞
}
public interface Cock {
public void gobble(); // 鸡的咕咕叫
public void fly(); // 飞
}
public class WildCock implements Cock {
public void gobble() {
System.out.println("咕咕叫");
}
public void fly() {
System.out.println("鸡也会飞哦");
}
}
鸭接口有 fly() 和 quack() 两个方法,鸡 Cock 如果要冒充鸭,fly() 方法是现成的,但是鸡不会鸭的呱呱叫,没有 quack() 方法。这个时候就需要适配了:
// 毫无疑问,首先,这个适配器肯定需要 implements Duck,这样才能当做鸭来用
public class CockAdapter implements Duck {
Cock cock;
// 构造方法中需要一个鸡的实例,此类就是将这只鸡适配成鸭来用
public CockAdapter(Cock cock) {
this.cock = cock;
}
// 实现鸭的呱呱叫方法
@Override
public void quack() {
// 内部其实是一只鸡的咕咕叫
cock.gobble();
}
@Override
public void fly() {
cock.fly();
}
}
类适配器模式:
HanlderAdapter真的采用了适配器模式么?
spring中大量使用到了适配器这种设计模式,就拿最经典的springMvc中的九大组件之一的 HanlderAdapter,从名字看就明白了这里十有八九用到了适配器模式但是叫Adapter就真的采用了适配器模式么??????看到百分之九十九的文章都打着适配器模式的幌子,但是本人并不认同:
- springmvc通过HandlerMapping获取到可以处理的handler,这些handler的类型各不相同,对请求的预处理,参数获取都不相同,最简单的做法是根据不同的handler类型,做一个分支处理,不同的handler编写不同的代码。这样的问题是很明显的,分支判断复杂,代码庞大,不符合单一职责原则。如果要增加一种handler类型,需要修改代码增加分支处理,违反了开闭原DispatcherServelt与多个handler发生了交互,违反迪米特法则。而使用适配器模式,就可以很好的解决这个问题。
- 不直接对handler进行处理,而是将handler交给适配器HandlerAdapter去处理,这样DispatcherServlet交互的类就只剩下一个接口,Handl erAdapter,符合迪米特法则,尽可能少的与其他类发生交互,将handler交给HandlerAdapter处理后,不同类型的handler被对应类型的Han dlerAdapter处理,每个HandlerAdapter都只完成单一的handler处理,符合单一职责原则。
public interface HandlerAdapter {
/**
* 判断是否可以使用某个handler
*/
boolean supports(Object handler);
/**
* 具体使用handler干活
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* 获取资源最后一次修改的时间戳
*/
long getLastModified(HttpServletRequest request, Object handler);
}
adapter的作用就是当请求过来时,使用实现了controller接口的的处理器来干活。干活的方法是直接调用处理器的handleRequest ( HttpSer vletRequest request, HttpServletResponse response)方法。这里我们可以看出对应不同的请求supports和getLastModified两个方法都是一样的。但是handle处理方法却要因请求的方式不同而异。HttpRequestHandlerAdapter、SimpleServletHandlerAdapter和Simple Controller Adapter分别适配了HttpRequestHandler、Servlet和Controller类型的Handler方法非常简单都是调用Handler里的固定方法。选择哪个Handl erAdapter的过程在getHandlerAdapter方法中,它的逻辑是遍历所有的Adapter,然后检查哪个可以处理当前的handler,找到第一个可以处理Handler的Adapter后停止查找并将其返回。HttpRequestHandlerAdapter
DispatcherServlet中的doDispatch方法:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
。。。。。。。。。。。。。。。
try {
// 检查请求有没有携带二进制文件,如何有则需要在http请求头中进行申明Multipart-form-data
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request. 确定当前请求的处理程序
// 1.获得当前请求的handler,在通常情况下其实就是controller对象但不完全一定是
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// getHandler方法主要会调用已经注册好了的handlerMapping中的getHandler方法
// Determine handler adapter for the current request.
// 2.根据找到的handler找到对应的handlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
。。。。。。。。。。。。。。。。。。。。。。。。。。。。
}
这样假设如果我们增加一个HardController,就要在代码中加入一行 if(mappedHandler.getHandler() instanceof HardController)
这种形式就使得程序难以维护,也违反了设计模式中的开闭原则 – 对扩展开放,对修改关闭。 因此Spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类, 让适配器代替controller执行相应的方法。这样在扩展Controller 时,只需要增加一个适配器类就完成了SpringMVC的扩展了。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/**
* {@link AbstractController#handleRequest(HttpServletRequest, HttpServletResponse)}
*/
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
可以明显的看到在获取适配器时是通过不断遍历,调用supports方法使用instanceof 关键字来进行判断的。如果符合则返回对应适配器类。
SimpleServletHandlerAdapter:
@Override
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
SimpleControllerHandlerAdapter:
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
HttpRequestHandlerAdapter:
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
到这里我认为,HandlerAdapter 本身和适配器设计模式并不沾边,不过设计模式本身也只是一种思想并不固定。