原创

设计模式-适配器模式

现实生活中适配器例子.png

工作原理

  1. 将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容。
  2. 从用户的角度看不到被适配者,是解耦的。
  3. 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法。
  4. 用户收到反馈结果,感觉只是和目标接口交互。

类适配器模式-手机充电Demo

家庭标准用电电压是220V,假设我手机充电只需要5V的,我就需要在220V标准电压上买一个充电头(适配器)给手机充电使用。

被适配的类Voltage220V:

/**
 * 被适配的类
 *
 * @author lzhpo
 */
public class Voltage220V {

    /**
     * 输出220V电压
     *
     * @return {int} src
     */
    public int output220V() {
        int src = 220;
        System.out.println("电压=" +src +"伏");
        return src;
    }
}

适配接口IVoltage5V:

/**
 * 适配接口
 *
 * 提供我们要用的方法
 *
 * @author lzhpo
 */
public interface IVoltage5V {
    public int output5V();
}

适配器类VoltageAdapter:

/**
 * 适配器类
 *
 * @author lzhpo
 */
public class VoltageAdapter extends Voltage220V implements IVoltage5V {

    /**
     * 将220V转换成5V
     *
     * @return dstV
     */
    @Override
    public int output5V() {
        int srcV = output220V();
        // 转成5V
        int dstV = srcV / 44;
        return dstV;
    }
}

给手机使用Phone:

/**
 * 给手机使用
 *
 * @author lzhpo
 */
public class Phone {

    /**
     * 手机充电
     *
     * @param iVoltage5V
     */
    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());
    }
}

运行结果:

---------------类适配器模式---------------
电压=220伏
电压为5V,可以充电!

注意事项和细节

  1. Java是单继承机制,所以类适配器需要继承src类这一点算是一个缺点, 因为这要求dst必须是接口,有一定局限性。
  2. src类的方法在Adapter中都会暴露出来,也增加了使用的成本。
  3. 由于其继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增强了。

对象适配器模式

  1. 基本思路和类的适配器模式相同,只是将Adapter类作修改,不是继承src类,而是持有src类的实例,以解决兼容性的问题。 即:持有 src类,实现 dst 类接口,完成src->dst的适配。
  2. 根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系。
  3. 对象适配器模式是适配器模式常用的一种。

手机充电Demo

还是前面手机充电那个例子。

被适配的类Voltage220V:

/**
 * 被适配的类
 *
 * @author lzhpo
 */
public class Voltage220V {

    /**
     * 输出220V电压
     *
     * @return {int} src
     */
    public int output220V() {
        int src = 220;
        System.out.println("电压=" +src +"伏");
        return src;
    }
}

适配接口:

/**
 * 适配接口
 *
 * 提供我们要用的方法
 *
 * @author lzhpo
 */
public interface IVoltage5V {
    public int output5V();
}

适配器类VoltageAdapter:

/**
 * 适配器类
 *
 * @author lzhpo
 */
public class VoltageAdapter implements IVoltage5V {

    /**
     * 关联关系 - 聚合
     */
    private Voltage220V voltage220V;

    /**
     * 通过构造器,传入一个Voltage220V实例
     *
     * @param voltage220V Voltage220V实例
     */
    public VoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    /**
     * 使用对象适配器
     *
     * @return dst
     */
    @Override
    public int output5V() {
        int dst = 0;
        if (null != voltage220V) {
            int src = voltage220V.output220V();
            System.out.println("使用对象适配器,进行适配!");
            dst = src / 44;
            System.out.println("适配完成,输出电压为=" +dst);
        }
        return dst;
    }
}

给手机使用Phone:

/**
 * 给手机使用
 *
 * @author lzhpo
 */
public class Phone {

    /**
     * 手机充电
     *
     * @param iVoltage5V
     */
    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) {
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter(new Voltage220V()));
    }
}

运行结果:

电压=220伏
使用对象适配器,进行适配!
适配完成,输出电压为=5
电压为5V,可以充电!

注意事项和细节

  1. 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口。
  2. 使用成本更低,更灵活。

接口适配器模式

接口适配器模式介绍

  1. 一些书籍称为缺省适配器模式。
  2. 核心思路:当不需要全部实现接口提供的方法时候,可以先设计一个抽象类实现接口,并为该接口每个方法提供一个默认实现(空方法),那么该抽象类可以有选择地覆盖某些方法来实现需求。
    1. 适用于一个接口不想使用其所有的方法的情况。

接口适配器模式Demo

Interface4接口的4个方法:

public interface Interface4 {
    public void m1();
    public void m2();
    public void m3();
    public void m4();
}

抽象类AbsAdapter默认实现Interface4中的方法,空方法:

/**
 * 在AbsAdapter将Interface4的方法进行默认实现
 * 
 * @author lzhpo
 */
public abstract class AbsAdapter implements Interface4 {
    @Override
    public void m1() {

    }

    @Override
    public void m2() {

    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }
}

测试使用:

public class Client {
    public static void main(String[] args) {
        AbsAdapter absAdapter = new AbsAdapter() {
            // 只需要去覆盖我们需要使用的接口方法
            @Override
            public void m1() {
                System.out.println("使用了m1的方法!");
            }
        };
        absAdapter.m1();
    }
}

运行结果:

使用了m1的方法!

SpringMVC中的适配器模式

获取HandlerAdapter的getHandlerAdapter()方法:

SpringMVC中的DispatchServlet的getHandlerAdapter方法.png

    /**
     * <p>
     * 【getHandlerAdapter获取HandlerAdapter】
     * 传入一个handler,根据需要返回适当的HandlerAdapter。
     *
     * 使用了适配器模式。
     *
     * </p>
     *
     * 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 {
        // 如果HandlerAdapter集合不为空
        if (this.handlerAdapters != null) {
            // 遍历此servlet使用的HandlerAdapter集合
            for (HandlerAdapter ha : this.handlerAdapters) {
                // 当前如果启用了跟踪日志记录
                if (logger.isTraceEnabled()) {
                    // 打印日志
                    logger.trace("Testing handler adapter [" + ha + "]");
                }
                // 传入的handler是否支持此HandlerAdapter?支持的话就返回
                if (ha.supports(handler)) {
                    return ha;
                }
            }
        }
        // 如果HandlerAdapter集合为空,就抛出异常提示
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

doDispatch处理实际分派给处理程序:

SpringMVC中的DispatchServlet的doDispatch方法.png

    /**
     *
     * <p>
     * 【doDispatch处理实际分派给处理程序】
     *
     * 传入HttpServletRequest和HttpServletResponse
     *
     * 通过按顺序应用servlet的HandlerMappings可以获得处理程序。 通过查询Servlet的已安装HandlerAdapters获得HandlerAdapter查找第一个支持处理程序类的对象。
     * 所有HTTP方法均由该方法处理。由HandlerAdapters或处理程序自己决定可接受的方法。
     * </p>
     *
     * Process the actual dispatching to the handler.
     * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
     * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
     * to find the first that supports the handler class.
     * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
     * themselves to decide which methods are acceptable.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     */
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

        // 把传入的request请求赋给新创建的HttpServletRequest
        HttpServletRequest processedRequest = request;
        // 处理程序执行链
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        // 获取当前请求,如果获取不到创建该请求并将其与请求关联。
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            // 初始化一个ModelAndView
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                // 将请求转换为多部分请求,并使多部分解析器可用。如果未设置多部分解析器,则只需使用现有请求。
                // processedRequest就是新创建的HttpServletRequest,也就是传入的request。
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                // mappedHandler为处理程序执行链,获取结果
                mappedHandler = getHandler(processedRequest);
                // 结果为空
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                // 获取当前请求的处理程序适配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                // 获取请求的方法
                String method = request.getMethod();
                // GET类型
                boolean isGet = "GET".equals(method);
                // 如果是GET类型或者方法是HEAD类型
                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;
                }

                // Actually invoke the handler.
                // 通过适配器调用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);
                }
            }
        }
    }

SpringMVC五大组件

  1. DispatcherServlet:前端控制器
    用户请求到达前端控制器,它就相当于mvc模式中的c,DispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。
  2. HandlerMapping:处理器映射器
    HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
  3. Handler(Controller):处理器
    Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
  4. HandlAdapter:处理器适配器
    通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
  5. ViewResolver:视图解析器
    ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
    • View(JSP):视图
      SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

参考链接:https://www.javatt.com/p/32454

实现一个简易版SpringMVC/DispatchServlet中央处理器

Controller:

package com.lzhpo.adapter.springmvcdemo;

/**
 * 多种Controller实现
 */
public interface Controller {

}

class HttpController implements Controller {
    public void doHttpHandler() {
        System.out.println("http...");
    }
}

class SimpleController implements Controller {
    public void doSimplerHandler() {
        System.out.println("simple...");
    }
}

class AnnotationController implements Controller {
    public void doAnnotationHandler() {
        System.out.println("annotation...");
    }
}

HandlerAdapter:

package com.lzhpo.adapter.springmvcdemo;

/**
 * 定义一个Adapter接口
 */
public interface HandlerAdapter {
    public boolean supports(Object handler);

    public void handle(Object handler);
}

/**
 * 多种适配器类
 */
class SimpleHandlerAdapter implements HandlerAdapter {

    @Override
    public void handle(Object handler) {
        ((SimpleController) handler).doSimplerHandler();
    }

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof SimpleController);
    }

}

class HttpHandlerAdapter implements HandlerAdapter {

    @Override
    public void handle(Object handler) {
        ((HttpController) handler).doHttpHandler();
    }

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof HttpController);
    }

}

class AnnotationHandlerAdapter implements HandlerAdapter {

    @Override
    public void handle(Object handler) {
        ((AnnotationController) handler).doAnnotationHandler();
    }

    @Override
    public boolean supports(Object handler) {

        return (handler instanceof AnnotationController);
    }

}

DispatchServlet:

package com.lzhpo.adapter.springmvcdemo;

import java.util.ArrayList;
import java.util.List;

/**
 * 简易版SpringMVC/DispatchServlet中央处理器
 *
 * @author lzhpo
 */
public class DispatchServlet {

    public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();

    public DispatchServlet() {
        handlerAdapters.add(new AnnotationHandlerAdapter());
        handlerAdapters.add(new HttpHandlerAdapter());
        handlerAdapters.add(new SimpleHandlerAdapter());
    }

    /**
     * 相当于SpringMVC中的doDispatch处理实际分派给处理程序
     */
    public void doDispatch() {
        // 此处模拟SpringMVC从request取handler的对象,
        // 适配器可以获取到希望的Controller
         HttpController controller = new HttpController();
        // AnnotationController controller = new AnnotationController();
        //SimpleController controller = new SimpleController();
        // 得到对应适配器
        HandlerAdapter adapter = getHandler(controller);
        // 通过适配器执行对应的controller对应方法
        adapter.handle(controller);
    }

    /**
     * 相当于SpringMVC中的获取请求的HandlerAdapter
     * @param controller
     * @return
     */
    public HandlerAdapter getHandler(Controller controller) {
        //遍历:根据得到的controller(handler), 返回对应适配器
        for (HandlerAdapter adapter : handlerAdapters) {
            if (adapter.supports(controller)) {
                return adapter;
            }
        }
        return null;
    }

    public static void main(String[] args) {
        new DispatchServlet().doDispatch(); // http...
    }

}

SpringMVC-Demo-1.png

正文到此结束
本文目录