设计模式之结构型模式中的适配器模式(Adapter Pattern)
基本介绍
适配器模式分类
适配器模式主要分为三类:类适配器、对象适配器、接口适配器。类适配器和对象适配器在实现上有些差别,而接口适配器则差别较大。
类适配器模式
类适配器实现的原理主要是通过继承。适配器类(Adapter)通过继承需要被适配的类(Source),实现需要得到的类(Destination)接口,从而完成 Adapter 到 Destination 的适配。
日常举例
手机充电的例子,通过手机充电器(Adapter)完成 220V 电源(Source)到 5V 电压(Destination)的转换
1 | public class Source220V { |
1 | public interface Destination5V { |
1 | public class VoltageAdapter extends Source220V implements Destination5V{ |
1 | public class Client { |
对象适配器模式
对象配器实现的原理主要是通过组合或聚合。在《设计模式七大原则之合成复用原则 (Composite Reuse Principle)》中,合成复用原则指出尽量使用合成 / 聚合,尽量不要使用类继承。对象适配器模式思路和类适配器模式基本相同,只不过将适配器类(Adapter)做修改,不再继承需要被适配的类(Source),而是直接持有需要被适配的类(Source),实现需要得到的类(Destination)接口,从而完成 Adapter 到 Destination 的适配。
日常举例
仍然是手机充电的例子,只需要修改适配器类(Adapter),如下:
1 | public class VoltageAdapter implements Destination5V{ |
1 | public class Client { |
接口适配器模式
接口配器实现的原理主要是通过抽象类来实现适配。接口适配器模式的核心思路是,当不需要全部实现接口的方法时,可以先设计一个抽象的类实现接口,并为接口中的每个方法提供一个默认的实现,对于该抽象类的子类就可以有选择的覆盖父类的某些方法,从而达到适配的目的。因此,该模式也被称为缺省适配器模式或是默认适配器模式(Default Adapter Pattern)。
日常举例
仍然是手机充电的例子,代码实现如下:
1 | public interface Destination { |
1 | public abstract class AbstractVoltageAdapter implements Destination{ |
1 | public class VoltageAdapter extends AbstractVoltageAdapter{ |
1 | public class Client { |
适配器模式在 Spring 框架中的应用
对于 SpringMVC 有一个很重要的 servlet,它有一个方法:
org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
截取部分源码如下:
源码:org.springframework.web.servlet.DispatcherServlet(片段)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class DispatcherServlet extends FrameworkServlet {
...
/**
* Return the HandlerAdapter for this handler object.
* @param handler the handler object to find an adapter for
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
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;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
...
}
源码:org.springframework.web.servlet.HandlerAdapter1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public interface HandlerAdapter {
/**
* Given a handler instance, return whether or not this {@code HandlerAdapter}
* can support it. Typical HandlerAdapters will base the decision on the handler
* type. HandlerAdapters will usually only support one handler type each.
* <p>A typical implementation:
* <p>{@code
* return (handler instanceof MyHandler);
* }
* @param handler handler object to check
* @return whether or not this object can use the given handler
*/
boolean supports(Object handler);
/**
* Use the given handler to handle this request.
* The workflow that is required may vary widely.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler to use. This object must have previously been passed
* to the {@code supports} method of this interface, which must have
* returned {@code true}.
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or {@code null} if the request has been handled directly
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* Same contract as for HttpServlet's {@code getLastModified} method.
* Can simply return -1 if there's no support in the handler class.
* @param request current HTTP request
* @param handler handler to use
* @return the lastModified value for the given handler
* @see javax.servlet.http.HttpServlet#getLastModified
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified
*/
long getLastModified(HttpServletRequest request, Object handler);
}
再看 HandlerAdapter 的继承关系图:
分析: 从上面的源码片段及 HandlerAdapter 的继承关系图,可以看出 Spring 定义了一个适配接口 HandlerAdapter,而其实现子类使得每一种 Controller 都有一种对应的适配器实现类,扩展 Controller 时只需增加对应的适配器实现类就可以了。
附:本次演示的项目地址
https://github.com/syshlang/java-design-patterns