适配器模式
基本介绍
- 适配器模式将某个类的接口转换成客户端期望的另一个接口表示,主要的目的是提高兼容性,让接口不匹配的类可以协同工作;别名为包装器Wrapper
- 适配器模式属于结构型模式
- 主要分类:类适配器模式、对象适配器模式、接口适配器模式
工作原理
- 将一个接口转成另一个接口,使原来不兼容的类可以兼容
- 用户角度看不到适配器,是解耦的
- 用户调用的是适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
- 用户收到反馈结果,感觉就是和目标接口交互
- Target目标,Adapter适配器,Source被适配者
类适配器
基本介绍
- Adapter类,通过集成src类,实现dst类接口,完成src到dst适配
业务举例
- 200v交通过变压器转5v直流电
代码实现
被适配目标
// 适配接口
public class Voltage220V {
// 输出220v电压
public int output220V() {
int src = 220;
System.out.println("电压= " + src + "伏");
return src;
}
}
适配接口
// 适配接口
public interface IVoltage5V {
public int output5V();
}
适配器类
// 适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V{
@Override
public int output5V() {
int srcV = output220V();
int dstV = srcV/44;
return dstV;
}
}
手机
// 手机
public class Phone {
// 充电
public void charging(IVoltage5V iVoltage5V) {
if (iVoltage5V.output5V() == 5) {
System.out.println("电压5V,可以充电");
} else if(iVoltage5V.output5V() > 5) {
System.out.println("电压大于5V,不能充电");
}
}
}
客户端
// 客户端
public class Client {
public static void main(String[] args) {
System.out.println("===========类适配器模式===========");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
}
}
注意事项和细节
- Java是单继承制,所以类适配器需要集成src类是一个缺点,这要求适配接口dst必须是接口
- src类的方法在Adapter中都会暴露出来,增加了使用成本
- 由于类适配器继承了src类,所以可以根据需求重写src方法,增加了Adapter的灵活性
对象适配器
基本介绍
- 基本思路和类适配器模式相同;区别在于,Adapter不再继承src类,而是持有src实例,实现dst接口,来解决适配问题
- 根据合成复用原则,系统中尽量使用关联关系来替代继承关系
- 对象适配器模式是适配器模式常用的一种
代码实现
被适配目标
/ 适配接口
public class Voltage220V {
// 输出220v电压
public int output220V() {
int src = 220;
System.out.println("电压= " + src + "伏");
return src;
}
}
适配接口
// 适配接口
public interface IVoltage5V {
public int output5V();
}
对象适配器类
// 适配器类
public class VoltageAdapter implements IVoltage5V {
private Voltage220V voltage220V;
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int output5V() {
int dstV = 0;
if (voltage220V != null) {
int srcV = voltage220V.output220V();
System.out.println("使用对象适配器转换");
dstV = srcV/44;
System.out.println("适配完成,输出电压为=" + dstV + "V");
}
return dstV;
}
}
手机
// 手机
public class Phone {
// 充电
public void charging(IVoltage5V iVoltage5V) {
if (iVoltage5V.output5V() == 5) {
System.out.println("电压5V,可以充电");
} else if(iVoltage5V.output5V() > 5) {
System.out.println("电压大于5V,不能充电");
}
}
}
客户端
// 客户端
public class Client {
public static void main(String[] args) {
System.out.println("===========对象适配器模式===========");
Phone phone = new Phone();
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
注意事项和细节
- 对象适配器和类适配器属于同一种思想,只是实现方式不同;
- 组合代替继承,解决了类适配器必须继承src的局限性问题,不再要求dst必须为借口
- 使用成本低,灵活
接口适配器
基本介绍
- 也称为适配器模式,缺省适配器模式
- 如果不需要全部实现接口方法时,可以先设计一个抽象类实现接口,并为该接口中的每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法类实现需求
- 适用于实现一个接口却不想使用其所有方法的情况
SpringMVC源码分析—HandlerAdapter
org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
getHandlerAdapter()就是根据不同的handler返回不同的适配器,
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
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");
}
getHandlerAdapter内进行遍历,找到合适的适配器返回
public interface HandlerAdapter {}
适配器接口下面有多个具体的实现类
因此,HandlerAdapter的实现子类,使得每一种Controller都有一种对应的适配器实现类,每种Controller有不同的实现方式
扩展Controller时,只需增加一个适配器类就完成了SpringMVC的扩展了,这就是设计模式的力量
适配器模式注意事项和细节
- 三种命名方式是根据src已怎样的形式给到Adapter来决定的
- 类适配器:在Adapter里,将src作为类继承
- 对象适配器:在Adapter里,将src作为一个对象持有
- 接口适配器:在Adapter里,将src作为一个接口实现
- Adapter最大的作用将原本不兼容的接口融合在一起工作