沉梦听雨的编程指南 沉梦听雨的编程指南
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 设计须知

  • UML画图

  • 权限校验

  • 设计模式

    • 设计模式基础入门
    • 设计模式七大原则
    • 单例模式
    • 工厂模式
    • 原型模式
    • 建造者模式
    • 适配器模式
      • 现实生活中的适配器例子
      • 基本介绍
      • 工作原理
      • 类适配器模式
        • 类适配器模式应用实例
        • 代码实现
        • 客户端(Client)
        • 实体类(Phone)
        • 适配接口(IVoltage5V)
        • 适配器类(VoltageAdapter)
        • 被适配的类(Voltage220V)
        • 时序图
        • 类适配器模式注意事项和细节
      • 接口适配器模式
        • 基本介绍
        • 接口(Interface4)
        • 抽象类(AbsAdapter)
        • 客户端(Client)
        • 时序图
      • 对象适配器模式
        • 基本介绍
        • 应用实例
        • 代码实现
        • 客户端(Client)
        • 实体类(Phone)
        • 适配接口(IVoltage5V)
        • 适配器类(VoltageAdapter)
        • 被适配的类(Voltage220V)
        • 时序图
        • 对象适配器模式注意事项和细节
      • 适配器模式在 SpringMVC 框架应用的源码剖析
        • 什么是 HandlerAdapter?
        • HandlerAdapter 的主要方法:
        • 适配器模式的应用
        • HandlerAdapter 的实现子类:
        • 源码分析
        • 调度类(DispatcherServlet)
        • 适配接口(HandlerAdapter)
        • 适配器类(SimpleControllerHandlerAdapter)
      • 模拟手写 SpringMVC
        • 调度类(DispatcherServlet)
        • 适配接口(HandlerAdapter)
        • 多种 Controller 实现
      • 适配器模式的注意事项和细节
      • 学习参考
    • 桥接模式
    • 装饰者模式
    • 外观模式
    • 模板方法模式
    • 常见设计模式总结
    • 设计模式 13 问
  • 系统设计
  • 设计模式
沉梦听雨
2024-11-24
3.7k
15.8m
目录
现实生活中的适配器例子
基本介绍
工作原理
类适配器模式
类适配器模式应用实例
代码实现
客户端(Client)
实体类(Phone)
适配接口(IVoltage5V)
适配器类(VoltageAdapter)
被适配的类(Voltage220V)
时序图
类适配器模式注意事项和细节
接口适配器模式
基本介绍
接口(Interface4)
抽象类(AbsAdapter)
客户端(Client)
时序图
对象适配器模式
基本介绍
应用实例
代码实现
客户端(Client)
实体类(Phone)
适配接口(IVoltage5V)
适配器类(VoltageAdapter)
被适配的类(Voltage220V)
时序图
对象适配器模式注意事项和细节
适配器模式在 SpringMVC 框架应用的源码剖析
什么是 HandlerAdapter?
HandlerAdapter 的主要方法:
适配器模式的应用
HandlerAdapter 的实现子类:
源码分析
调度类(DispatcherServlet)
适配接口(HandlerAdapter)
适配器类(SimpleControllerHandlerAdapter)
模拟手写 SpringMVC
调度类(DispatcherServlet)
适配接口(HandlerAdapter)
多种 Controller 实现
适配器模式的注意事项和细节
学习参考

适配器模式

# 适配器模式

# 现实生活中的适配器例子

泰国插座用的是两孔的(欧标),可以买个多功能转换插头(适配器),这样就可以使用了。

# 基本介绍

  1. 适配器模式 (Adapter Pattern) 将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器 (Wrapper)
  2. 适配器模式属于结构型模式
  3. 主要分为三类:类适配器模式、接口适配器模式、对象适配器模式

# 工作原理

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

image

# 类适配器模式

基本介绍:Adapter 类,通过继承 src 类,实现 dst 类接口,完成 src -> dst 的适配。

# 类适配器模式应用实例

应用实例说明:

  • 以生活中充电器的例子来讲解适配器,充电器本身相当于 Adapter,220V 交流电相当于 src(即被适配者),我们的 dst(即目标)是 5V 直流电

# 代码实现

# 客户端(Client)

public class Client {

    public static void main(String[] args) {
        System.out.println(" === 类适配器模式 ====");
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());
    }

}
1
2
3
4
5
6
7
8
9

# 实体类(Phone)

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, 不能充电~~");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 适配接口(IVoltage5V)

public interface IVoltage5V {

    int output5V();
}
1
2
3
4

# 适配器类(VoltageAdapter)

public class VoltageAdapter extends Voltage220V implements IVoltage5V {

	@Override
	public int output5V() {

		// 获取到 220V 电压
		int srcV = output220V();

		// 转成 5v
		return srcV / 44;
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 被适配的类(Voltage220V)

public class Voltage220V {

    // 输出220V的电压
    public int output220V() {
        int src = 220;
        System.out.println("电压=" + src + "伏");
        return src;
    }
}
1
2
3
4
5
6
7
8
9

# 时序图

classadapter

# 类适配器模式注意事项和细节

  1. Java 是单继承机制,所以 类适配器 需要继承 src 类这一点算是一个缺点,因为这要求 dst 必须是接口,有一定局限性

  2. src 类的方法在 Adapter 中都会暴露出来,也增加了使用的成本。

  3. 由于其继承了 src 类,所以它可以根据需求重写 src 类的方法,使得 Adapter 的灵活性增强了。

类适配器:VoltageAdapter

src:Voltage220V

dst:IVoltage5V

# 接口适配器模式

# 基本介绍

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

# 接口(Interface4)

public interface Interface4 {

	void m1();

	void m2();

	void m3();

	void m4();
}
1
2
3
4
5
6
7
8
9
10

# 抽象类(AbsAdapter)

/**
 * 在 AbsAdapter 我们将 Interface4 的方法进行默认实现
 *
 * @author chenmeng
 */
public abstract class AbsAdapter implements Interface4 {

	// 默认实现
	@Override
    public void m1() {

	}

	@Override
	public void m2() {

	}

	@Override
	public void m3() {

	}

	@Override
	public void m4() {

	}
}
1
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

# 客户端(Client)

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

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 时序图

interfaceadapter

# 对象适配器模式

# 基本介绍

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

# 应用实例

以生活中充电器的例子来讲解适配器,充电器本身相当于 Adapter,220V 交流电相当于 src(即被适配者),我们的 dst(即目标)是 5V 直流电,使用对象适配器模式完成。

# 代码实现

对比 类适配器模式,只有 适配器类 进行了修改,使用关联关系(聚合)来替代继承关系

# 客户端(Client)

public class Client {

	public static void main(String[] args) {
		System.out.println(" === 对象适配器模式 ====");
		Phone phone = new Phone();
		phone.charging(new VoltageAdapter(new Voltage220V()));
	}

}
1
2
3
4
5
6
7
8
9

# 实体类(Phone)

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, 不能充电~~");
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11

# 适配接口(IVoltage5V)

public interface IVoltage5V {

    int output5V();
}
1
2
3
4

# 适配器类(VoltageAdapter)

public class VoltageAdapter implements IVoltage5V {

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

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

    @Override
    public int output5V() {
        int dst = 0;

        if (null != voltage220V) {
            // 获取220V 电压
            int src = voltage220V.output220V();
            System.out.println("使用对象适配器,进行适配~~");
            dst = src / 44;
            System.out.println("适配完成,输出的电压为=" + dst);
        }

        return dst;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 被适配的类(Voltage220V)

public class Voltage220V {

    // 输出220V的电压
    public int output220V() {
        int src = 220;
        System.out.println("电压=" + src + "伏");
        return src;
    }
}
1
2
3
4
5
6
7
8
9

# 时序图

objectadapter

# 对象适配器模式注意事项和细节

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

# 适配器模式在 SpringMVC 框架应用的源码剖析

  1. SpringMVC 中的 HandlerAdapter, 就使用了适配器模式

  2. SpringMVC 处理请求的流程回顾

    • Spring 定义了一个适配接口,使得每一种 Controller 有一种对应的适配器实现类
    • 适配器代替 Controller 执行相应的方法
    • 扩展 Controller 时,只需要增加一个适配器类就完成了 SpringMVC 的扩展了,
  3. 使用 HandlerAdapter 的原因分析:

    • 可以看到处理器的类型不同,有多重实现方式,那么调用方式就不是确定的,
    • 如果需要直接调用 Controller 方法,需要调用的时候就得不断是使用 if else 来进行判断是哪一种子类然后执行。
    • 那么如果后面要扩展 Controller,就得修改原来的代码,这样违背了 OCP 开闭原则。

SpringMVC 的 Handler(Controller接口,HttpRequestHandler,Servlet、@RequestMapping)有四种表现形式,在 Handler 不确定是什么方式的时候(可能是方法、也可能是类),适配器这种设计模式就能模糊掉具体的实现,从而就能提供统一访问接口。

# 什么是 HandlerAdapter?

  • 在 SpringMVC 中,HandlerAdapter 是一个接口,它的作用是将请求的 Handler(控制器)适配到 SpringMVC 的框架中。
  • 由于 SpringMVC 支持多种类型的控制器,包括基于注解的控制器、基于接口的控制器等,每种控制器的调用方式都可能不同。
  • HandlerAdapter提供了一个统一的接口,使得 SpringMVC 可以以相同的方式调用不同类型的控制器。

# HandlerAdapter 的主要方法:

  • supports(Object handler):判断适配器是否支持给定的 Handler。
  • handle(HttpServletRequest request, HttpServletResponse response, Object handler):调用 Handler 处理请求。
  • getLastModified(HttpServletRequest request, Object handler):获取请求的最新修改时间。

# 适配器模式的应用

  1. SpringMVC 通过 HandlerAdapter 接口,为每种类型的控制器提供了一个 适配器实现类。
  2. 这样,当 DispatcherServlet 接收到请求时,它会根据请求找到相应的 Handler,然后通过 getHandlerAdapter 方法获取对应的 HandlerAdapter,
  3. 最后通过适配器调用控制器的方法。

# HandlerAdapter 的实现子类:

HandlerAdapter 的实现子类使得每一种 Controller 都有一种对应的适配器实现类,每种 Controller 有不同的实现方式

  1. AbstractHandlerMethodAdapter:

    • 这是一个抽象类,提供了一些基础的实现,用于简化具体 HandlerAdapter 的实现。它并不是直接用于处理请求,而是作为其他适配器的基类。
  2. HandlerFunctionAdapter:

    • 这个适配器用于适配基于 Java 8 函数式接口的处理器,例如 java.util.function.BiFunction。
  3. HttpRequestHandlerAdapter:

    • 用于适配实现了 HttpRequestHandler 接口的处理器。这种处理器比较少见,通常用于一些特殊的场景。
  4. RequestMappingHandlerAdapter:

    • 继承 AbstractHandlerMethodAdapter 类

    • 这是 Spring MVC 中最常用的适配器之一,用于适配带有 @RequestMapping 注解的控制器方法。它支持各种 HTTP 方法的映射,如 GET、POST 等。

  5. SimpleControllerHandlerAdapter:

    • 用于适配实现了Controller接口的处理器。这种适配器在 Spring MVC 中使用较少,因为 @Controller 注解更为常用。
  6. SimpleServletHandlerAdapter:

    • 用于适配实现了 Servlet 接口的处理器。这允许在 Spring MVC 中使用传统的 Servlet 作为控制器。

图示:

image

# 源码分析

# 调度类(DispatcherServlet)

public class DispatcherServlet extends FrameworkServlet {
    // ...
    
    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;
                Exception dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    // 通过 HandlerMapping 来映射 Controller
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    // 获取适配器
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = HttpMethod.GET.matches(method);
                    if (isGet || HttpMethod.HEAD.matches(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        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;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    Exception ex = var20;
                    dispatchException = ex;
                } catch (Throwable var21) {
                    Throwable err = var21;
                    dispatchException = new NestedServletException("Handler dispatch failed", err);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                Exception ex = var22;
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
            } catch (Throwable var23) {
                Throwable err = var23;
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }
    
    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }
    
    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (pageNotFoundLogger.isWarnEnabled()) {
            pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
        }

        if (this.throwExceptionIfNoHandlerFound) {
            throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request), (new ServletServerHttpRequest(request)).getHeaders());
        } else {
            response.sendError(404);
        }
    }

    // 根据需要,返回适当的 HandlerAdapter
    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");
    }

    // ...
}
1
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

# 适配接口(HandlerAdapter)

public interface HandlerAdapter {

    /**
     * 判断当前的HandlerAdapter是否支持给定的handler。
     * <p>这是确定是否使用当前适配器处理请求的关键方法。
     * 每个适配器通常只能适配一种特定类型的处理器,
     * 因此此方法用于检查给定的handler是否与适配器兼容。
     *
     * @param handler 需要处理的处理器对象
     * @return 如果适配器支持该handler,则返回true;否则返回false。
     */
    boolean supports(Object handler);

    /**
     * 核心方法:利用Handler处理请求,然后返回一个ModelAndView。
     * <p>DispatcherServlet最终就是调用此方法,来返回一个ModelAndView的。
     * 这个方法将请求委托给具体的handler处理,并接收处理结果,
     * 通常包括视图信息和模型数据。
     *
     * @param request 当前的HttpServletRequest对象,包含请求数据。
     * @param response 当前的HttpServletResponse对象,用于构造响应。
     * @param handler 需要处理请求的Handler对象。
     * @return ModelAndView对象,包含视图信息和模型数据。
     * @throws Exception 如果处理过程中发生异常,将被抛出。
     */
    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    /**
     * 同HttpServlet的getLastModified方法。
     * <p>用于确定请求资源的最后修改时间,以便进行缓存控制。
     * 如果处理器不支持最后修改时间的确定,此方法可以返回-1。
     * <p>注意:此方法已被弃用,建议使用其他机制实现缓存控制。
     *
     * @param request 当前的HttpServletRequest对象,包含请求数据。
     * @param handler 需要处理请求的Handler对象。
     * @return 资源的最后修改时间戳,或者-1表示不支持。
     * @deprecated 由于缓存控制的最佳实践已经变化,此方法不再推荐使用。
     */
    @Deprecated
    long getLastModified(HttpServletRequest request, Object handler);
}
1
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
41
42

# 适配器类(SimpleControllerHandlerAdapter)

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    public SimpleControllerHandlerAdapter() {
    }

    public boolean supports(Object handler) {
        return handler instanceof Controller;
    }

    @Nullable
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return ((Controller)handler).handleRequest(request, response);
    }

    public long getLastModified(HttpServletRequest request, Object handler) {
        return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 模拟手写 SpringMVC

# 调度类(DispatcherServlet)

public class DispatcherServlet {

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

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

	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);

	}

	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 DispatcherServlet().doDispatch(); // http...
	}

}
1
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

# 适配接口(HandlerAdapter)

public interface HandlerAdapter {

    boolean supports(Object handler);

    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);
    }
}
1
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
41
42
43
44
45
46
47
48
49
50
51

# 多种 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...");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 适配器模式的注意事项和细节

  1. 三种命名方式,是根据 src 是以怎样的形式给到 Adapter(在Adapter里的形式)来命名的。

    • 类适配器:以类给到,在 Adapter 里,就是将 src 当做类,继承

    • 对象适配器:以对象给到,在 Adapter 里,将 src 作为一个对象,持有

    • 接口适配器:以接口给到,在 Adapter 里,将 src 作为一个接口,实现

  2. Adapter 模式最大的作用还是将原本不兼容的接口融合在一起工作。

  3. 实际开发中,实现起来不拘泥于我们讲解的三种经典形式

# 学习参考

  • Spring MVC适配器模式实践之HandlerAdapter源码分析【享学Spring MVC】-腾讯云开发者社区-腾讯云 (opens new window)
上次更新: 2025/3/17 17:25:48
建造者模式
桥接模式

← 建造者模式 桥接模式→

Theme by Vdoing | Copyright © 2023-2025 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式