适配器设计模式(Adapter Pattern),顾名思义。创建一个类的适配器使之能够满足原本不兼容的接口需求。
适配器模式中两个重要角色:Adaptee(被适配者) , Adapter(适配者) ,Target(适配的接口或者类)
实现适配器模式方式主要有以下两种:
-
委托方式,
结构图如下:
-
继承模式
结构图如下:
这里推荐使用方式1
经典问题,给手机充电。 我国民用标准电压为220V(交流电) , 手机充电只需要5V(直流电) .因此就需要一个充电器(适配器)来做电流和电压的转换。
在Java代码中可以这样实现:
① 创建被适配器(220V交流电)。
public class Electricity220 {
public double outPut(){
return 220;
}
}
② 创建手机充电接口 target
public interface TelPhoneInterface {
double charge5();
}
③ 创建手机充电适配器 adapter
public class TelPhoneAdapter implements TelPhoneInterface {
private Electricity220 electricity220 ;
public TelPhoneAdapter(Electricity220 electricity220) {
this.electricity220 = electricity220;
}
@Override
public double charge5() {
return electricity220.outPut()/44;
}
}
测试代码:
public static void main(String[] args) {
double adapterElectricity = new TelPhoneAdapter(new Electricity220()).charge5();
System.out.println(adapterElectricity);
}
输出结果: 5.0
这个有点类似与装饰者模式,他们的区别是:适配器模式用于填补不同接口之间的差异。装饰者模式则是不改变接口。
适配器设计模式在spring源码中也有很多应用。比较经典的是spring MVC 中的HandlerAdapter 。
public interface HandlerAdapter {
//判断这个适配器是否能适配这个给定handler对象
boolean supports(Object handler);
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
在DispatcherServlet中的使用如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//根据对应请求的handler来获取对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
mappedHandler.applyPostHandle(processedRequest, response, mv);
}catch (Exception ex) {...}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {}finally {}
}
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");
}
可以看到,这个有点类似雨策略模式加适配器。 HandlerAdapter#supports就相当判断请求对应的handler应该用那个HandlerAdapter来拆箱。HandlerAdapter#handle才是真正的适配接口。
实际项目中,要尽量提前设计好接口。不到不得已建议不要使用适配器模式,容易增加代码的复杂程度。