设计模式系列----适配器模式理解

1、使用场景

1、适配器模式主要是用于把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作
2、多个组件功能类似,但接口不统一且可能会经常切换时,可使用适配器模式,使得客户端可以以统一的接口使用它们

2、什么是适配器模式

实际生活的例子就是家用电流220V手机充电器手机充电需要5V
三者的关系就是,手机充电器对家用电流进行适配封装,使得输入充电器的电流是220V,而输出给手机的电流是5V。

适配器模式共用三个角色:
Target(手机)
Adapter(手机充电器)
Adapetee(家用电流)

1、如果是类的适配器模式

步骤1: 创建Target接口(使用5V的手机)

public interface Target {

    //只能接受5V的工作电流(原有插头(Adaptee)没有的)
    public void work_with_5v();
}

步骤2: 创建Adaptee(输出220V的家用电器) ;

class  OutPut220V{
//原有插头只能输出220V
      public void output_220v(){
    }
}

步骤3:创建Adapter(手机充电器)

class Adapter220V extends OutPut220V  implements Target{
    @Override
    public void work_with_5v(){
    //重写了Target的work_with_5v方法,内部调用output_220v
      this.output_220v;
    }
}

步骤4:定义具体使用目标类,并通过Adapter类调用所需要的方法从而实现目标(不需要通过原有插头)

//进口机器类
class Phone{

    @Override
    public void work() {
        System.out.println("手机正常充电");
    }
}


//通过Adapter类从而调用所需要的方法
public class AdapterPattern {
    public static void main(String[] args){

        Target target= new Adapter220V();
        Phone phone= new Phone();
        target.work_with_5v();
        phone.work();
    }
}
2、如果是对象的适配器模式

与类的适配器模式相同的是,对象的适配器模式也是把适配的类的API转换成为目标类的API。
与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。

步骤1: 创建Target接口;

public interface Target {
 
    //这是源类Adapteee没有的方法
    public void Request(); 
}

步骤2: 创建源类(Adaptee) ;

public class Adaptee {
    
    public void SpecificRequest(){
    }
}

步骤3: 创建适配器类(Adapter)(不适用继承而是委派)

class Adapter implements Target{  
    // 直接关联被适配类  
    private Adaptee adaptee;  
    
    // 可以通过构造函数传入具体需要适配的被适配类对象  
    public Adapter (Adaptee adaptee) {  
        this.adaptee = adaptee;  
    }  
    
    @Override
    public void Request() {  
        // 这里是使用委托的方式完成特殊功能  
        this.adaptee.SpecificRequest();  
    }  
}  

步骤4:定义具体使用目标类,并通过Adapter类调用所需要的方法从而实现目标

public class AdapterPattern {
    public static void main(String[] args){
        //需要先创建一个被适配类的对象作为参数  
        Target mAdapter = new Adapter(new Adaptee());
        mAdapter.Request();
     
    }
}

与类的适配器模式的代码不同的就是:只是在适配类实现时将“继承”改成“在内部委派Adaptee类”而已


3、Spring MVC源码中的实际应用


然后我们看看在Spring MVC中源码的实际应用。
先复习一下SpringMVC的执行流程:

1、一个请求匹配前端控制器 DispatcherServlet 的请求映射路径(在 web.xml中指定), WEB 容器将该请求转交给 DispatcherServlet 处理

2、DispatcherServlet 接收到请求后, 将根据 请求信息 交给 处理器映射器 (HandlerMapping)
HandlerMapping 根据用户的url请求 查找匹配该url的 Handler,并返回一个执行链

3、DispatcherServlet 再请求 处理器适配器(HandlerAdapter) 调用相应的 Handler 进行处理并返回 ModelAndView 给 DispatcherServlet

4、DispatcherServlet 将 ModelAndView 请求 ViewReslover(视图解析器)解析,返回具体 View

5、DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)

6、DispatcherServlet 将页面响应给用户

可以看到在第三步中,使用了HandlerAdapter(处理器适配器) ,在学完适配器模式后,就应该对Adapter后缀的类名有很强的敏感度,一眼看过去就是使用了适配器模式,是为了使得两个无法一起工作的类,进过适配器适配后,能够一起工作。

适配器模式在 SpringMVC 中的经典使用体现在它的核心方法 doDispatch 方法中,再来看一个 Spring MVC 中的 HandlerAdapter 类,它也有多个子类,类图如下。

在这里插入图片描述
其适配调用的关键代码还是在 DispatcherServlet 的 doDispatch() 方法中,代码如下。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 此处通过HandlerMapping来映射Controller
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 获取适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 通过适配器调用controller的方法并返回ModelAndView
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception ex) {
            dispatchException = ex;
        } catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    } catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

在 doDispatch() 方法中调用了 getHandlerAdapter() 方法,代码如下。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        Iterator var2 = this.handlerAdapters.iterator();
        while (var2.hasNext()) {
            HandlerAdapter ha = (HandlerAdapter) var2.next();
            if (this.logger.isTraceEnabled()) {
                this.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");

}

–我是“道祖且长”,一个在互联网"苟且偷生"的Java程序员
“有任何问题,可评论,我看到就会回复”

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三七有脾气

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值